Android 中所有控件都直接或间接继承自 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/title_bg" >
<Button
android:id="@+id/title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dip"
android:background="@drawable/back_bg"
android:text="Back"
android:textColor="#000" />
<TextView
android:id="@+id/text_1"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:text="Title Text"
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="5dip"
android:background="@drawable/edit_bg"
android:text="Edit"
android:textColor="#000" />
</LinearLayout>
2. 在程序中使用这个标题栏
修改 activity_main.xml 中的代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- 该行 include 语句即可将标题栏布局引入进来 -->
<include layout="@layout/title"/>
</LinearLayout>
3. 隐藏系统标题栏
在 MainActivity 中将系统自带的标题栏隐藏掉,代码如下所示:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 隐藏系统自带标题栏
setContentView(R.layout.activity_main);
}
}
运行程序,效果如下图所示:
使用这种方式,不管有多少布局需要添加标题栏,只需一行 include 语句就可以了。
PS:效果图界面略差,仅供了解学习知识点。
若不隐藏系统标题栏,则二者都显示,如下图所示:
So,由于好奇,添加了 5 个 include 语句,修改 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:layout_height="match_parent"
android:orientation="vertical" >
<include layout="@layout/title"/>
<include layout="@layout/title"/>
<include layout="@layout/title"/>
<include layout="@layout/title"/>
<include layout="@layout/title"/>
</LinearLayout>
运行结果如图所示:
PS: 之前还好奇会是什么样,原来如此。
4. 创建自定义控件
新建 TitleLayout 继承自 LinearLayout,让它成为我们自定义的标题栏控件
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, AttributeSet attrs) {
super(context, attrs);
/*
* 通过 LayoutInflater 的 from()方法构建出一个 LayoutInflater对象,然后调用 inflate()方法动态加载一个布局文件
* inflate()方法接收两个参数:
* 第一个参数是要加载的布局文件的 id,这里传 R.layout.title
* 第二个参数是给加载好的布局再添加一个父布局, 这里指定为 TitleLayout,于是传 this
*/
LayoutInflater.from(context).inflate(R.layout.title, this);
}
// Q: 添加父布局是什么意思?
在布局文件中添加这个自定义控件,修改 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"
android:orientation="vertical"
<com.example.uifor.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
></com.example.uifor.TitleLayout>
</LinearLayout>
注意:
1. 需要指明控件的完整类名(此处为 com.example.uifor.TitleLayout)。
2. 这种方式加载的布局添加点击事件后才会有响应;而之前用 include 语句添加的无响应。
5. 添加事件处理
在 TitleLayout 的构造方法中添加按钮的点击事件。
为方便起见,这里只打印了一句话(具体功能可根据需要添加)。代码如下:
public TitleLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title, this);
Button back = (Button) findViewById(R.id.title_back);
Button edit = (Button) findViewById(R.id.title_edit);
back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(), "You clicked Back!", Toast.LENGTH_SHORT).show();
}
});
edit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(), "You clicked Edit!", Toast.LENGTH_SHORT).show();
}
});
}
运行程序,并点击 Edit 按钮,打印出文本,效果如图所示:
PS: 主要内容整理总结自《第一行代码》