Android開發之自定義組件和介面回調

来源:http://www.cnblogs.com/ludashi/archive/2016/06/07/5008785.html
-Advertisement-
Play Games

說到自定義控制項不得不提的就是介面回調,在Android開發中介面回調用的還是蠻多的。在這篇博客開始的時候呢,我想聊一下iOS的自定義控制項。在iOS中自定義控制項的思路是繼承自UIView, 在UIView的子類中組合一些控制項,對外暴漏一些屬性和回調介面,並留有必要的實現方法。在iOS自定義控制項中常用的 ...


說到自定義控制項不得不提的就是介面回調,在Android開發中介面回調用的還是蠻多的。在這篇博客開始的時候呢,我想聊一下iOS的自定義控制項。在iOS中自定義控制項的思路是繼承自UIView, 在UIView的子類中組合一些控制項,對外暴漏一些屬性和回調介面,並留有必要的實現方法。在iOS自定義控制項中常用的回調有兩種,一是委托代理回調(Delegate),另一種是Block回調。如果你想對這兩者有所瞭解,請參考我之前的博客《Objective-C中的委托(代理)模式》、《Objective-C中的Block回調模式》、《設計模式(十三):從“FQ”中來認識代理模式(Proxy Pattern)》。

在Android自定義控制項時用到的介面回調和iOS開發中使用到的Delegate回調以及Block回調即為相似,就連實現方式都大同小異。今天的內容就自定義一個Android控制項,並且以此控制項為基礎,聊一下Android中的介面回調(確切的說應該是Java語言中的介面回調)。廢話少說,進入今天的主題。

一.自定義控制項的UI實現

上面有提到,iOS開發中,自定義控制項一般式繼承自UIView的,然後再UIView的子類中做一些事情。而Android開發中的自定義控制項也是繼承自View, 但是今天我們的自定義控制項是繼承自FrameLayout, 在此基礎上我們自定義一些東西。因為FrameLayout, LinearLayout等佈局方式都是繼承自ViewGroup的,而ViewGroup則繼承自View, 所以在自定義控制項時,繼承自FrameLayout等佈局方式肯定是可以的。

1. 實現效果分析

接下來我們要自定義一個導航欄,而這個導航欄是模仿iOS系統中的NavigationBar。因為Android開發中沒有這個控制項,所以我們需要自定義這個控制項供開發者使用。下方是我們要實現的效果。上方的導航欄是我們自定義的NavigationBar,和iOS系統的導航欄類似。點擊左邊的返回按鈕,會退出當前Activity。點擊右邊的藉口回調測試,會通過介面回調的形式來在當前Activity中顯示Toast提示。在調用該組件時,可以知道中間的Title.

2. UI佈局分析以及Xml佈局文件實現

接下來我們將會對UI進行拆分,詳細的看一下上面的NavigationBar是由哪些基礎控制項組成的。分析完畢後,在通過一些佈局方式將這些基礎控制項進行組合,拼裝,最終成為我們想要使用的自定義控制項。下方是手動畫的上述自定義控制項UI原理圖,如下所示。

最下邊的佈局我們採用的時FrameLayout方式,並設置其背景顏色。返回圖標(ImageView)和 返迴文字(TextView)放在了一個水平佈局的LinearLayout上。這兩者上面放了一個透明的Button, 用來實現返回操作。中間的Title(TextView) 在FrameLayout中設置成居中顯示即可。Call Back是一個Button, 用來測試下麵的介面回調。

上面的佈局格式具體落實到xml中,如下所示,具體思想就是上方敘述的東西。該自定義控制項佈局文件如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <FrameLayout  xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="wrap_content"
 5     android:background="#cccccc">
 6     <LinearLayout
 7         android:orientation="horizontal"
 8         android:layout_width="match_parent"
 9         android:layout_height="20pt"
10         android:background="@drawable/background">
11         <ImageView
12             android:id="@+id/back_title"
13             android:layout_width="wrap_content"
14             android:layout_height="18pt"
15             android:layout_gravity="center"
16             android:src="@drawable/back"/>
17         <TextView
18             android:layout_width="wrap_content"
19             android:layout_height="wrap_content"
20             android:layout_gravity="center"
21             android:textSize="8pt"
22             android:text="返回"/>
23     </LinearLayout>
24 
25     <Button
26         android:id="@+id/back_button"
27         android:layout_width="50pt"
28         android:layout_height="20pt"
29         android:layout_gravity="center_vertical"
30         android:alpha="0" />
31 
32     <TextView
33         android:id="@+id/navigation_title"
34         android:layout_width="wrap_content"
35         android:layout_height="wrap_content"
36         android:textSize="10pt"
37         android:layout_gravity="center"
38         android:text="標題"/>
39 
40     <Button
41         android:id="@+id/call_back"
42         android:layout_width="wrap_content"
43         android:layout_height="wrap_content"
44         android:layout_gravity="right"
45         android:text="介面回調測試"/>
46 </FrameLayout>

 

 

二. 為UI綁定事件以及留出回調介面

UI實現好後,就說明我們自定義組件的殼兒已經做好了,但是其內在的東西還需要實現。也就是說需要為上述實現的UI綁定Java類,併在類中處理控制項的一些響應事件,以及在類中留出必要的介面來改變自定義組件的屬性。接下來來實現xml對應的Java類。

因為上述佈局中,最外層我們使用的是FrameLayout佈局,上面已經粗略的提過,我們可以繼承自FrameLayout來做一些東西,因為FrameLayout的父類是View, 所以我們可以在此基礎上做一些東西。同理,如果上述佈局是使用其他佈局來實現的,那麼你就可以繼承自其他佈局的類來做一些東西。在本篇博客中我們就以FrameLayout為父類來實現我們自定義組件的關聯類。

1. 繼承FrameLayout並實現相應的構造函數,下方是我們要實現的構造函數。在構造函數中,我們需要與上述我們實現的xml佈局文件進行關聯,當然,我們使用的是LayoutInflater來實現的,自定義組件的構造函數如下所示。

    /*
     *自定義組件的構造方法
     */
    public CustomNavigationBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater.from(context).inflate(R.layout.custom_navigation, this);     //載入佈局文件
    }

 

2. 實現好相應的構造方法並關聯好相應的佈局文件後,我們需要對佈局文件中的控制項進行事件的處理。下方的代碼就是點擊返回按鈕要做的事情,因為點擊返回按鈕要做的事情就是結束當前Activity,所以不需要給調用者留有回調介面,在自定義組件的內部處理即可。下方代碼就是獲取UI中返回按鈕,並處理返回事件的方法。下方的方法需要在構造函數中調用才會起作用,函數不調用怎麼執行呢,對吧~。 下方代碼較為簡單,就是結束當前顯示的Activity,處理返回按鈕的事件如下:

 1     /*
 2      * 點擊返回按鈕方法
 3      */
 4     private void onClickBackButton() {
 5         Button button = (Button) findViewById(R.id.back_button);
 6         button.setOnClickListener(new OnClickListener() {
 7             @Override
 8             public void onClick(View v) {
 9                 ((Activity) getContext()).finish();
10             }
11         });
12     }

    

3.處理好返回事件後,我們需要做的還有就是為標題欄的標題留出設置的方法。也就是說在調用該自定義組件時,我們要能設置該組件的標題。要滿足這一點,我們就需要在自定義組件中留出Title的setter方法了,並且這個Setter方法的訪問許可權必須是Public的,不然在外界就沒辦法訪問這個方法了。下方就是這個設置title的Public方法。其實下方的代碼還是比較簡單的,就是通過ID來獲取標題的TextView,並設置相應的title即可,代碼如下:

 1     public String navigationTitle = "標題欄";
 2 
 3     /*
 4      * 設置標題欄的標題
 5      */
 6     public void setNavigationTitle(String navigationTitle) {
 7         this.navigationTitle = navigationTitle;
 8         TextView textView = (TextView) findViewById(R.id.navigation_title);
 9         textView.setText(navigationTitle);
10     }

 

4. 上面如果還算簡單的話,下方就是自定義控制項中稍稍有點難度的地方了。接下來我們要實現相應按鈕的介面回調,在實現之前我們介紹一下為什麼要實現介面的回調。因為有時候點擊自定義控制項中的按鈕時,所做的事情在自定義控制項的內部無法獨立完成,需要在調用者中進行事件的處理,在這種情況下,我們就可以使用介面回調來處理。

上面實現的返回事件的處理就沒必要使用介面的回調了,因為在自定義組件內部完全可以該功能。舉個使用介面回調的慄子:比如點擊自定義控制項中某個按鈕時,我們需要跳轉到其他Activity,而這個Activity在我們實現自定義控制項時是未知的,這時候就要用到我們的介面回調來實現了。在iOS開發中,同樣遇到上述問題,所以iOS開發中也有各種回調比如Block回調,Delegate回調,Target-Action回調等都是iOS開發中常用的回調。雖然實現形式不同,但是其作用和Java中的介面回調是極為相似的。好,說這麼多,接下來我們要為XML佈局文件中id為call_back的按鈕的點擊事件通過介面回調的形式傳遞到調用者中。

(1)第一步我們要先實現介面回調的介面,這也是必須的,因為介面回調如果沒有介面怎麼能行呢。該介面是Public類型的,不然在調用者中是無法使用的。我們介面的名字為onClickCallBackListener, 在其中有一個方法,該方法是介面回調時要執行的方法。

1     /*
2      *創建回調介面
3      */
4     public static interface OnClickCallBackListener {
5         public void OnClickButton(View v);
6     }

 

(2) 聲明一個私有的介面對象,併為這個私有的對象實現setter方法,該私有的介面對象是用來接受自定義組件調用者傳過來的回調方法的。代碼比較簡單,在此就不做過多贅述了。

1     private OnClickCallBackListener callBackListener;            //聲明介面對象
2     public void setCallBackListener(OnClickCallBackListener callBackListener) {
3         this.callBackListener = callBackListener;
4     }

 

(3) 實現好介面以及接收回調對象的變數後,接下來要做的事情就是獲取自定義組件中相應按鈕點擊的事件,併在此按鈕點擊事件中執行傳過來的介面對象相應的回調方法。下方這個方法,要在構造函數中調用。該方法的功能就是獲取自定義組件的相應按鈕的點擊事件並執行介面對象的回調方法。具體實現如下:

    /*
     *點擊按鈕時執行介面回調
     */
    private void callBackButton() {
        Button button = (Button) findViewById(R.id.call_back);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (callBackListener != null) {
                    callBackListener.OnClickButton(v);
                }
            }
        });
    }

 

上方是把代碼拆開來講的,下方是整個自定義組件的實現類。具體代碼如下所示。

 1 package com.example.lizelu.customnavigationbar;
 2 
 3 import android.annotation.TargetApi;
 4 import android.app.Activity;
 5 import android.content.Context;
 6 import android.os.Build;
 7 import android.util.AttributeSet;
 8 import android.view.LayoutInflater;
 9 import android.view.View;
10 import android.widget.Button;
11 import android.widget.FrameLayout;
12 import android.widget.TextView;
13 
14 /**
15  * Created by lizelu on 15/11/29.
16  */
17 public class CustomNavigationBar extends FrameLayout {
18 
19     /*
20      *創建回調介面
21      */
22     public static interface OnClickCallBackListener {
23         public void OnClickButton(View v);
24     }
25 
26 
27     private OnClickCallBackListener callBackListener;            //聲明介面對象
28 
29     public String navigationTitle = "標題欄";
30 
31     /*
32      * 設置標題欄的標題
33      */
34     public void setNavigationTitle(String navigationTitle) {
35         this.navigationTitle = navigationTitle;
36         TextView textView = (TextView) findViewById(R.id.navigation_title);
37         textView.setText(navigationTitle);
38     }
39 
40     public void setCallBackListener(OnClickCallBackListener callBackListener) {
41         this.callBackListener = callBackListener;
42     }
43 
44     /*
45      *自定義組件的構造方法
46      */
47     public CustomNavigationBar(Context context, AttributeSet attrs) {
48         super(context, attrs);
49         LayoutInflater.from(context).inflate(R.layout.custom_navigation, this);     //載入佈局文件
50         onClickBackButton();
51         callBackButton();
52     }
53     /*
54      * 點擊返回按鈕方法
55      */
56     private void onClickBackButton() {
57         Button button = (Button) findViewById(R.id.back_button);
58         button.setOnClickListener(new OnClickListener() {
59             @Override
60             public void onClick(View v) {
61                 ((Activity) getContext()).finish();
62             }
63         });
64     }
65 
66     /*
67      *點擊按鈕時執行介面回調
68      */
69     private void callBackButton() {
70         Button button = (Button) findViewById(R.id.call_back);
71         button.setOnClickListener(new OnClickListener() {
72             @Override
73             public void onClick(View v) {
74                 if (callBackListener != null) {
75                     callBackListener.OnClickButton(v);
76                 }
77             }
78         });
79     }
80 }
View Code

 

 

三.該自定義組件的調用方式

經過上面的過程,我們自定控制項以及實現好了,接下來就是如何使用了。其實自定義組件的使用方式和系統自帶的組件使用起來區別不大,沒有什麼特別之處。下方就讓我們在Activity中使用上述我們自定義的控制項吧。

1.首先在我們要使用該組件的Activity所對應的佈局文件中載入我們的自定義組件的佈局。要註意的一點是自定義組件的標簽我們要使用包的全面才可以,其他的和Android的系統組件使用方法類似,具體代碼如下:

1         <com.example.lizelu.customnavigationbar.CustomNavigationBar
2             android:id="@+id/custom_navigation_bar"
3             android:layout_width="match_parent"
4             android:layout_height="wrap_content"/>

 

2.在Activity的Java類中,通過id獲取我們自定義組件的對象,並實現其相應的回調即可。具體代碼如下:

 1     private void setNavigationTitle(String title) {
 2         CustomNavigationBar navigationBar = (CustomNavigationBar) findViewById(R.id.custom_navigation_bar);
 3         navigationBar.setNavigationTitle(title);
 4 
 5         //實現組件上的按鈕的介面回調
 6         navigationBar.setCallBackListener(new CustomNavigationBar.OnClickCallBackListener() {
 7             @Override
 8             public void OnClickButton(View v) {
 9                 Toast.makeText(MainActivity.this, "回調執行的方法", Toast.LENGTH_SHORT).show();
10             }
11         });
12     }

到此,自定義組件的實現和調用實現完畢。雖然上述自定義控制項雖然比較簡單,但是麻雀雖小,五臟俱全。再複雜的自定義控制項也是有簡單的東西慢慢的拼裝而成。所以理解自定義控制項的實現原理還是比較重要的。今天的博客就先到這兒,下方是上述Demo在GitHub上的分享地址,需要的小伙伴請自行Clone。

github分享地址:https://github.com/lizelu/AndroidCustomNavigationBar

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 效果說明:配合已有CSS樣式,載入插件後,網頁元素可以隨意在視窗內拖拽,設置了原位置半透明和拖拽半透明的效果選項,可根據需要選擇。另外,當頁面上有多個可拖拽元素時,可以載入另外一個用於設置z-index的插件,模擬Windows視窗點擊置頂效果。 js/jquery.jLdraggable.js: ...
  • 每個學過編程的人都寫過“HelloWorld” 但99乘法表,我想也應該成為每個編程初學者的必編程式 這是JavaScript的實現方法,非常適合初學者!!! 以下是代碼及註釋 1 <!DOCTYPE html> 2 <head> 3 <meta http-equiv="Content-Type" ...
  • 在頁面中除了內容圖片以外的圖片都是修飾圖,去掉無意義修飾圖或者用css替換秀試圖效果是減少HTTP請求次數的有效方式。 一:css替換圖片 圓角 陰影 漸變 等css效果在當前主瀏覽器中已得到廣泛的支持,而在之前是通過圖片來實現這些效果的,比如圓角按鈕 圓角按鈕相對來說只需要要一次HTTP請求,但是 ...
  • 在HTML頁面中插入Javascript的主要方法,就是使用<script>元素。這個元素由Netscape創造併在Netscape Navigator 2中首先實現。後來,這個元素就被加入到正式的HTML規範中。HTML4.01為<script>定義了6個屬性,包括defer和async。defe ...
  • 本篇主要簡單介紹了knockoutjs中各種綁定的使用方法,使用這些綁定方法的組合就能簡單地做好一個需要較多動態交互的UI頁面。使用這些方法比較重要的一點就是要記住綁定的都是函數對象,所以可以直接在HTML裡面進行操作,這樣的話有時候 js 代碼結構可以更簡單。 ...
  • iOS 直播 閃光燈的使用 應用場景是這樣的,最近公司決定做一款直播類的軟體. 在開發中就遇到了不曾使用過的硬體功能 閃光燈. 這篇博客將簡單介紹一下閃光燈的使用. ` ` ...
  • 1.第一個Fragment 2.第二個Fragment ...
  • iOS FFmpeg 優秀博客(資源)集錦 這篇博客沒有我自己寫的內容: 主要是對FFmpeg一些優秀博客的記錄 隨時更新 1 "iOS編譯FFmpeg,kxmovie實現視頻播放" 2 "視音頻編解碼技術零基礎學習方法" 3 "一個不依賴FFmpeg的播放器,支持RTMP" ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...