我们所用的所有控件都是直接或间接继承自 View的,所用的所有布局都是直接或间接继承自 ViewGroup 的。View 是 Android 中一种最基本的 UI 组件,它可以在屏幕上绘制一块矩形区域,并能响应这块区域的各种事件,因此,我们使用的各种控件其实就是在 View的基础之上又添加了各自特有的功能。而 ViewGroup 则是一种特殊的 View,它可以包含很多的子 View 和子 ViewGroup,是一个用于放置控件和布局的容器。
创建自定义控件的两种简单方法。先将准备工作做好,创建一个 UICustomViews 项目。
引入布局
创建一个自定义的标题栏。加入两个 Button 和一个 TextView。一般我们的程序中可能有很多个活动都需要这样的标题栏,如果在每个活动的布局中都编写一遍同样的标题栏代码,明显就会导致代码的大量重复。这个时候我们就可以使用引入布局的方式来解决这个问题,新建一个布局 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="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="5dip"
android:text="Back"
android:textColor="#fff" />
<TextView
android:id="@+id/title_text"
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:textColor="#f0f"
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:text="Edit"
android:textColor="#fff" />
</LinearLayout>
我们在LinearLayout中分别加入了两个Button和一个TextView,左边的Button可用于返回,右边的 Button 可用于编辑,中间的 TextView 则可以显示一段标题文本。
修改 activity_main.xml 中的代码,如下所示:
<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 中将系统自带的标题栏隐藏掉,代码如下所示:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
}
创建自定义控件
新建 TitleLayout 继承自 LinearLayout,让它成为我们自定义的标题栏控件,代码如下所示:
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, 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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="pub.weber.bym.uicustomviews.MainActivity">
<include layout="@layout/title"/>
<pub.weber.bym.uicustomviews.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
</pub.weber.bym.uicustomviews.TitleLayout>
</LinearLayout>
添加自定义控件和添加普通控件的方式基本是一样的,只不过在添加自定义控件的时候我们需要指明控件的完整类名,包名在这里是不可以省略的。
重新运行程序,你会发现此时效果和使用引入布局方式的效果是一样的。
然后我们来尝试为标题栏中的按钮注册点击事件,修改 TitleLayout中的代码,如下所示:
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, 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 v) {
((Activity) getContext()).finish();
}
});
titleEdit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(),"你点击了编辑按钮",Toast.LENGTH_SHORT).show();
}
});
}
}
首先还是通过 findViewById()方法得到按钮的实例,然后分别调用 setOnClickListener()方法给两个按钮注册了点击事件,当点击返回按钮时销毁掉当前的活动,当点击编辑按钮时弹出一段文本。重新运行程序,点击一下编辑按钮,效果如图所示。