View元件及UI介面控制方法
View及ViewGroup類介紹
簡介
Android應用的所有UI元件都繼承了View類,View元件非常類似於Swing程式設計中的JPanel,它代表了一個空白的矩形區域,View元件沒有任何內容。對於Android應用的其它UI元件來說,它們都繼承了View元件,然後在View元件提供的空白區域上繪製外觀。
Android採用了”組合器“設計模式來設計View和ViewGroup,ViewGroup作為View的重要子類,通用作為其它元件的容器使用。
自定義元件的方法
當Android系統提供的UI元件不足以滿足專案需要時,開發者可以通過繼承View來派生自定義元件。在自定義元件時,通常被重寫的方法(實際開發中只重寫部分
- 構造器。重寫構造器是定製View的最基本方式,當Java程式碼建立一個View例項或根據XML佈局檔案載入並構建介面時將需要呼叫該構造器。
- onFinishInflate()。當應用從XML佈局檔案載入該元件並利用它來構建介面之後,該方法就會被回撥。
- onMeasure(int, int)。該方法用來檢測View元件及它所包含的所有子元件的大小。
- onLayout(boolean, int, int, int, int)。當該元件需要分配其子元件的位置、大小時,該方法就會被回撥。
- onSizeChanged(int, int, int, int)。當該元件的大小被改變時回撥該方法。
- onDraw(Canvas)。當該元件將要繪製它的內容時回撥該方法進行繪製。
- onKeyDown(int, KeyEvent)。當某個鍵被按下時觸發該方法。
- onKeyUp(int, KeyEvent)。當鬆開某個鍵時觸發該方法。
- onTrackballEvent(MotionEvent)。當發生軌跡球事件時觸發該方法。
- onTouchEvent(MotionEvent)。當發生觸控式螢幕事件時觸發該方法。
- onWindowFocusChanged(boolean)。當該元件得到、失去焦點時觸發該方法。
- onAttachedToWindow()。當把該元件放入某個視窗時觸發該方法。
- onDetachedFromWindow()
- onWindowVisibilityChanged(int)。當包含該元件的視窗的可見性發生變化時觸發該方法。
UI介面控制方法
Android推薦使用XML佈局檔案來定義使用者介面,而不是使用Java程式碼來開發使用者介面。Android中控制組件的方式有如下兩種:
- 在XML佈局檔案中通過XML屬性進行控制。
- 在Java程式程式碼中通過呼叫方法進行控制。
上述兩種方法控制Android使用者介面行為的本質是一樣的,通常情況下,控制UI元件的XML屬性還有對應的方法。下面就對這兩種方法進行簡單介紹:
使用XML佈局檔案控制UI介面
Android推薦使用XML佈局檔案來控制檢視,這樣不僅簡單、明瞭,而且可以將應用的檢視控制邏輯從Java程式碼中分離出來,更好地體現了MVC原則。
當應用在res/layout
目錄下定義一個主檔名任意的XML佈局檔案之後,R.java
會自動收錄此佈局資源。
setContentView(R.layout.<資原始檔名字>) //在Activity中顯示該檢視
findViewById(R.id.<android.id屬性值>) //通過ID獲取UI元件,之後就可以通過程式碼來控制此UI元件的外觀行為了(如為UI元件繫結事件監聽器等)。
在程式碼中控制UI介面
如果希望程式碼中控制UI介面,我們可以完全拋棄XML佈局檔案 ,而將所有的UI元件都通過new關鍵字創建出來,然後以合適的方式”搭建“在一起即可。
public class CodeView extends Activity {
//當第一次建立該Activity時回撥該方法
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//建立一個線性佈局管理器
LinearLayout layout = new LinearLayout(this);
//設定該Activity顯示layout
super.setContentView(layout);
layout.setOrientation(LinearLayout.VERTICAL);
//建立一個TextView
final TextView show = new TextView(this);
//建立一個按鈕
Button bn = new Button(this);
bn.setText(R.string.ok);
bn.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
//向Layout容器中新增TextView
layout.addView(show);
//向Layout容器中新增按鈕
layout.addView(bn);
//為按鈕繫結一個事件監聽器
bn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
show.setText("Hello, Android, " + new java.util.Date());
}
});
}
}
完全在程式碼中控制UI介面不僅不利於高層次的解耦,而且由於通過new關鍵字來建立UI元件,需要呼叫方法來設定UI元件的行為,因此程式碼也顯得十分臃腫。相反,如果通過XML檔案來控制UI介面,開發者只要在XML佈局檔案中使用標籤即可建立UI元件,而且只要配置簡單的屬性即可控制UI元件的行為,因此要簡單得多。
使用XML佈局檔案和Java程式碼混合控制UI介面
完全使用程式碼來控制UI介面不僅煩瑣,而且不利於解耦;而完全利用XML佈局檔案來控制UI介面雖然方便、便捷,但難免有失靈活。
當混合使用XML佈局檔案和程式碼來控制UI介面時,習慣上把變化 小、行為比較固定的元件放在XML佈局檔案中管理,而那些變化較多、行為控制比較複雜的元件則交給Java程式碼來管理。
我們可以通過先在佈局檔案中定義一個簡單的線性佈局容器,然後在程式獲取該容器,並往該容器中新增元件。此程式的功能是週期性展示定義在drawable下面的圖片,展示中觸發切換的操作是點選當前圖片。具體程式碼如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="miss.picturewall.PictureWall">
<LinearLayout
android:id="@+id/root"
android:layout_width="368dp"
android:layout_height="495dp"
android:orientation="vertical"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp"></LinearLayout>
</android.support.constraint.ConstraintLayout>
public class PictureWall extends AppCompatActivity {
//定義一個訪問圖片的陣列
int[] images = new int[]{
R.drawable.jiajia,
R.drawable.jiajia1,
R.drawable.jiajia2,
R.drawable.jiajia3,
R.drawable.jiajia4,
R.drawable.jiajia5
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//獲取LinearLayout佈局容器
LinearLayout main = (LinearLayout)findViewById(R.id.root);
//程式建立ImageView元件
final ImageView image = new ImageView(this);
//將ImageView元件新增到LinearLayout佈局容器中
main.addView(image);
//初始化時顯示第一張圖片
image.setImageResource(images[0]);
image.setOnClickListener(new View.OnClickListener() {
int currentImg = 0;
@Override
public void onClick(View v) {
currentImg = (currentImg + 1) % images.length;
//改變ImageView裡顯示的圖片
image.setImageResource(images[currentImg]);
}
});
}
}
自定義元件例項
一個小球跟隨手指的程式。主要有以下三個檔案
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="miss.fingerball.CustomView">
<LinearLayout
android:id="@+id/root"
android:layout_width="368dp"
android:layout_height="495dp"
android:orientation="vertical"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp"></LinearLayout>
</android.support.constraint.ConstraintLayout>
public class BallView extends View {
public float currentX = 40;
public float currentY = 50;
public BallView(Context context) {
super(context);
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
//建立畫筆
Paint p = new Paint();
//設定畫筆顏色
p.setColor(Color.RED);
//繪製一個小球
canvas.drawCircle(currentX, currentY, 15, p);
}
}
public class CustomView extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout root = (LinearLayout)findViewById(R.id.root);
//建立BallView元件
final BallView ball = new BallView(this);
//設定自定義元件的最小寬度、高度
ball.setMinimumWidth(root.getWidth());
ball.setMinimumHeight(root.getHeight());
//為ball元件繫結Touch事件
ball.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//修改ball元件的currentX、currentY兩個屬性
ball.currentX = event.getX();
ball.currentY = event.getY();
//通知ball元件重繪
ball.invalidate();
return true;
}
});
root.addView(ball);
}
}
摘自《瘋狂Android講義》