Android中View組件的作用類似於Swing變成中的JPanel,它只是一個空白的矩形區域,View組件中沒有任何內容。對於Android應用的其他UI組件來說,它們都繼承了View組件,然后在View組件提供的空白區域繪制外觀。
當Android系統提供的UI組件不足以滿足項目需求時,我們可以通過繼承View並重寫View類的一個或多個方法來自定義組件。
通常可以被用戶重寫的方法如下:
1.構造器:重寫構造器是定制View的最基本的方式,當Java(或Kotlin)代碼創建一個View實例或根據XML布局文件加載並構建界面時將調用該構造器。
2.onFinishInflate():這是一個回調方法,當應用從XML布局文件加載該組件並利用它來構建界面之后,該方法將會被調用。
3.onMeasure(int,int):調用該方法來檢測View組件及其所包含的所有子組件的大小。
4.onLayout(boolean,int,int,int,int):當該組件需要分配其子組件的位置、大小時,該方法就會被回調。
5.onSizeChanged(int,int,int,int):當該組件的大小被改變時回調該方法。
6.onDraw(Canvas):當該組件將要繪制它的內容時回調該方法。
7.onKeyDown(int,KeyEvent):當按下某個鍵時觸發該方法。
8.onKeyUp(int,KeyEvent):當松開某個鍵時觸發該方法。
9.onTrackballEvent(MotionEvent):當發生軌跡球事件時觸發該方法
10.onTouchEvent(MotionEvent):當發生觸摸屏事件時觸發該方法
11.onFocusChanged(boolean gainFocus,int direction,Rect previouslyFocusedRect):當該組件焦點發生改變時觸發該方法。
12.onWindowFocusChanged(boolean):當包含該組件的窗口失去或得到焦點時觸發該方法。
13.onAttachedToWindow():當把該組件放入某個窗口中時觸發該方法
14.onDetachedFromWindow():當把該組件從某個窗口中分離時觸發該方法
15.onWindowVisibilityChanged(int):當包含該組件的窗口的可見性發生改變時觸發該方法。
當我們在開發自定義View時,通常僅需根據業務需求重寫上面的部分方法,如果自定義組件僅僅只是組合現有的組件那就更加簡單了,僅僅實現自定義組件的構造器然后使用LayoutInflater加載布局文件即可。
⒈實例自定義View
1 package cn.coreqi.view; 2 3 import android.content.Context; 4 import android.graphics.Canvas; 5 import android.graphics.Color; 6 import android.graphics.Paint; 7 import android.util.AttributeSet; 8 import android.view.MotionEvent; 9 import android.view.View; 10 11 public class DrawView extends View { 12 private float currentX = 40f; 13 private float currentY = 50f; 14 15 //定義並創建畫筆 16 private Paint p = new Paint(); 17 18 public DrawView(Context context) { 19 super(context); 20 } 21 22 public DrawView(Context context, AttributeSet attrs) { 23 super(context, attrs); 24 } 25 26 //當該組件將要繪制它的內容時觸發該方法 27 @Override 28 protected void onDraw(Canvas canvas) { 29 super.onDraw(canvas); 30 //設置畫筆的顏色 31 p.setColor(Color.RED); 32 //繪制一個小圓(作為小球) 33 canvas.drawCircle(currentX,currentY,15F,p); 34 } 35 36 //為該組件的觸碰事件重寫事件處理方法 37 @Override 38 public boolean onTouchEvent(MotionEvent event) { 39 //修改currentX,currentY兩個成員變量 40 currentX = event.getX(); 41 currentY = event.getY(); 42 //通知當前組件重新繪制自己 43 invalidate(); 44 //返回true表明該處理方法已經處理該事件 45 return true; 46 } 47 }
⒉在代碼中創建自定義View
1 package cn.coreqi; 2 3 import androidx.appcompat.app.AppCompatActivity; 4 5 import android.os.Bundle; 6 import android.widget.LinearLayout; 7 import cn.coreqi.view.DrawView; 8 9 10 public class MainActivity extends AppCompatActivity { 11 12 @Override 13 protected void onCreate(Bundle savedInstanceState) { 14 super.onCreate(savedInstanceState); 15 //新建LinearLayout布局容器 16 LinearLayout layout = new LinearLayout(this); 17 //設置該Activity顯示layout 18 setContentView(layout); 19 //創建我們自定義的View組件 20 DrawView draw = new DrawView(this); 21 //設置自定義組件的最小寬度、高度 22 draw.setMinimumWidth(300); 23 draw.setMinimumHeight(500); 24 layout.addView(draw); 25 } 26 }
⒊在XML布局文件中創建自定義View
1 <?xml version="1.0" encoding="utf-8"?> 2 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context=".MainActivity"> 8 9 <cn.coreqi.view.DrawView 10 android:id="@+id/drawView" 11 android:layout_width="match_parent" 12 android:layout_height="match_parent" /> 13 14 </androidx.constraintlayout.widget.ConstraintLayout>