所有的控件都是直接或間接繼承自View的,所用的所有布局都是直接或間接繼承自ViewGroup的。View是Android中最基本的一種UI元件,它可以在螢幕繪制一塊矩形區域,并能響應這塊區域的各種事件,是以,我們使用的各種控件其實都是在View的基礎之上又添加了各自特有的功能。而ViewGroup是一種特殊的View,它可以包含很多子View和子ViewGroup,是一個用于放置控件和布局的容器。
1.引入布局
如果我們多次用到一個重複的布局,那麼就可以使用引入布局來解決這個問題。建立一個布局title.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#2454ce"
android:layout_height="wrap_content">
<Button
android:id="@+id/title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="@drawable/back"
android:textColor="#fff"
android:text="back"
/>
<TextView
android:id="@+id/title_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:text="Tittle Text"
android:textColor="#000000"
android:textSize="24sp"
/>
<Button
android:id="@+id/title_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="@drawable/edit"
android:text="Edit"
android:textColor="#fff"
/>
</LinearLayout>
然後再修改activity_main.xml中的代碼,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/title"/>
</LinearLayout>
最後在MainActivity中将系統自帶的标題欄隐藏掉
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar=getSupportActionBar();
if(actionBar!=null){
actionBar.hide();
}
}
}
效果如下
建立自定義控件
引入布局的技巧确實解決了重複編寫布局代碼的問題,但是如果布局中有一些控件要求能夠響應事件,我們還是需要在每個活動中為這些控件單獨編寫一次事件注冊的代碼。比如說标題欄中的傳回按鈕。
建立TitleLayout繼承自LinearLayout,讓它成為我們自定義的标題欄控件,代碼如下:
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title,this);
}
}
重寫了LinearLayout中帶有兩個參數的構造函數,在布局中引入TitleLayout控件就會調用這個構造函數。然後在構造函數中需要對标題欄布局進行動态加載,這就要借助LayoutInflater來實作了。通過LayoutInflater的from()方法可以建構出一個LayoutInflater對象,然後調用inflate()方法就可以動态加載一個布局檔案,inflate()方法接收兩個參數,第一個參數是要加載的布局id,這裡我們傳入R.layout.title,第二個參數是給加載好的布局再添加一個父布局,這裡我們想要指定為TitleLayout,于是直接傳入this.
然後我們需要在布局檔案中直接加入這個自定義控件,修改activity_main.xml中的代碼,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.john.uilayouttest.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
為标題欄中的按鈕注冊點選事件,修改TitleLayout中的代碼,如下所示:
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title,this);
Button titleBack=(Button)findViewById(R.id.title_back);
Button titleEdit=(Button)findViewById(R.id.title_edit);
titleBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
((Activity)getContext()).finish();
}
});
titleEdit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getContext(),"You clicked Edit button",Toast.LENGTH_SHORT).show();
}
});
}
}