在实际开发过程中,我们会碰到许多这种界面
下面来介绍怎样封装成为一个通用的控件
1.首先新建一个类,在这里继承自FrameLayout,实现对应的构造方法
public class ItemGroup extends FrameLayout{
public ItemGroup(Context context) {
super(context);
}
public ItemGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ItemGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
2.属性的定义,在完成类的创建后,来自定义相关属性
首先需要在values目录下面新建一个attrs.xml文件 , 自定义相关属性,在这里定义了一个标题文字,文字左右的图片,最右边的图片,分割线,分割线颜色这几个属性。
<declare-styleable name="ItemGroup">
<attr name="title" format="string"/>
<attr name="drawable_left" format="reference"/>
<attr name="drawable_right" format="reference"/>
<attr name="line_color" format="color"/>
<attr name="line_height" format="integer"/>
declare-styleable>
其定义格式如下:
<declare-styleable name="自定义属性名称">
<attr name="属性名称" format="属性类型"/>
declare-styleable>
属性类型主要包括:
reference 引用
color 颜色
boolean 布尔值
dimension 尺寸值
float 浮点值
integer 整型值
string 字符串
enum 枚举值
3 属性的引入,在定义完属性后,接下来将定义的属性值引入到类中
/**
* 初始化,引入相关属性
* @param context
* @param attrs
*/
private void initAttrs(Context context,AttributeSet attrs){
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ItemGroup);
strTitle = typedArray.getString(R.styleable.ItemGroup_title);
drawableLeft = typedArray.getDrawable(R.styleable.ItemGroup_drawable_left);
drawableright = typedArray.getDrawable(R.styleable.ItemGroup_drawable_right);
lineHeight = typedArray.getInt(R.styleable.ItemGroup_line_height,1);
lineColor = typedArray.getColor(R.styleable.ItemGroup_line_color,0xff999999);
typedArray.recycle();
}
在这里,通过obtainStyledAttributes方法获取到一个TypedArray对象,然后通过TypedArray对象就可以获取到相对应定义的属性值(相关原理性的东西,此处略过)
4 引入自定义布局,相关代码如下,在此需要引入一个布局文件
/**
* 控件初始化
*/
private void initView(Context context){
mView = LayoutInflater.from(context).inflate(R.layout.view_item,null);
rlItemGroup = (RelativeLayout)mView.findViewById(R.id.rl_item_group);
tvTitle = (TextView) mView.findViewById(R.id.tv_title);
ivRight = (ImageView)mView.findViewById(R.id.iv_right);
line = mView.findViewById(R.id.line);
this.addView(mView);
rlItemGroup.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(itemOnClickListener != null){
itemOnClickListener.onClick(v);
}
}
});
}
注意: 在此必须通过 this.addView(mView); 将引入的布局添加到当前的布局里
view_item.xml布局文件相关代码如下:
<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="#ffffff"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/rl_item_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="16dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="12dp"
android:gravity="center_vertical" />
<ImageView
android:id="@+id/iv_right"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" />
RelativeLayout>
<View
android:id="@+id/line"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/line_default_color" />
LinearLayout>
5 将引入的属性值应用到引入的布局控件上。
在此,设置左边的图片,通过TextView的 leftDrawable来实现
if(drawableLeft != null){
drawableLeft.setBounds(0, 0, 72, 72); //此处大小可以根据实际需求设置,在此只做一个演示
tvTitle.setCompoundDrawables(drawableLeft, null, null, null);
}
6.在布局文件里面使用,在完成上面的步骤以后,就可以在布局文件里面使用了
"http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#e8e8e8"
android:orientation="vertical">
<com.mirko.customeitem.view.ItemGroup
android:id="@+id/ig_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:drawable_left="@drawable/menu_home"
app:drawable_right="@drawable/arrow_right"
app:title="首页" />
android在使用的时候,需要引入命名空间,引入方法为:
xmlns:前缀 = http : //schemas.android.com/apk/res/自定义View所在的包路径.
注意:此种引入方式在Android Studio里面使用的时候会提示一个错误:
in Gradle projects,always use http : //schemas.android.com/apk/res-auto for custom attributes
所以在Android Studio里面我们使用
xmlns:前缀 = http : //schemas.android.com/apk/res-auto就可以给相关属性赋值了。
7.添加每一项的点击事件
/**
* 创建点击事件监听
*/
public interface ItemOnClickListener{
public void onClick(View v);
}
ItemOnClickListener itemOnClickListener;
public void setItemOnClickListener(ItemOnClickListener itemOnClickListener){
this.itemOnClickListener = itemOnClickListener;
}
通过此接口回调,就可以实现点击事件。
在Activity里面我们就可以设置点击事件
ItemGroup igHome = (ItemGroup)findViewById(R.id.ig_home);
igHome.setItemOnClickListener(new ItemGroup.ItemOnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"当前点击了首页",Toast.LENGTH_SHORT).show();
}
});
至此整个封装已经完成 。
相关完整代码如下:
/**
* Created by Mirko on 2016/11/8.
*/
public class ItemGroup extends FrameLayout{
private RelativeLayout rlItemGroup;
private View mView;
private TextView tvTitle;
private ImageView ivRight;
private View line;
private String strTitle;
private Drawable drawableLeft;
private Drawable drawableright;
private int lineHeight;
private int lineColor;
public ItemGroup(Context context) {
super(context);
}
public ItemGroup(Context context, AttributeSet attrs) {
super(context, attrs);
init(context,attrs);
}
public ItemGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
private void init(Context context,AttributeSet attrs){
initView(context);
initAttrs(context,attrs);
setData();
}
/**
* 初始化,引入相关属性
* @param context
* @param attrs
*/
private void initAttrs(Context context,AttributeSet attrs){
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ItemGroup);
strTitle = typedArray.getString(R.styleable.ItemGroup_title);
drawableLeft = typedArray.getDrawable(R.styleable.ItemGroup_drawable_left);
drawableright = typedArray.getDrawable(R.styleable.ItemGroup_drawable_right);
lineHeight = typedArray.getInt(R.styleable.ItemGroup_line_height,1);
lineColor = typedArray.getColor(R.styleable.ItemGroup_line_color,0xff999999);
typedArray.recycle();
}
/**
* 控件初始化
*/
private void initView(Context context){
mView = LayoutInflater.from(context).inflate(R.layout.view_item,null);
rlItemGroup = (RelativeLayout)mView.findViewById(R.id.rl_item_group);
tvTitle = (TextView) mView.findViewById(R.id.tv_title);
ivRight = (ImageView)mView.findViewById(R.id.iv_right);
line = mView.findViewById(R.id.line);
this.addView(mView);
rlItemGroup.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(itemOnClickListener != null){
itemOnClickListener.onClick(v);
}
}
});
}
private void setData(){
tvTitle.setText(strTitle);
if(drawableLeft != null){
drawableLeft.setBounds(0, 0, 72, 72);
tvTitle.setCompoundDrawables(drawableLeft, null, null, null);
}
if(drawableright != null){
ivRight.setImageDrawable(drawableright);
}
line.setBackgroundColor(lineColor);
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,lineHeight));
rlItemGroup.setBackgroundResource(R.drawable.xml_click);
}
/**
* 创建点击事件监听
*/
public interface ItemOnClickListener{
public void onClick(View v);
}
ItemOnClickListener itemOnClickListener;
public void setItemOnClickListener(ItemOnClickListener itemOnClickListener){
this.itemOnClickListener = itemOnClickListener;
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private ItemGroup igHome;
private ItemGroup igSoft;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ItemGroup igHome = (ItemGroup)findViewById(R.id.ig_home);
ItemGroup igSoft = (ItemGroup)findViewById(R.id.ig_soft);
igHome.setItemOnClickListener(new ItemGroup.ItemOnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"当前点击了首页",Toast.LENGTH_SHORT).show();
}
});
igSoft.setItemOnClickListener(new ItemGroup.ItemOnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"当前点击了软件介绍",Toast.LENGTH_SHORT).show();
}
});
}
}
activity_main.xml
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#e8e8e8"
android:orientation="vertical">
<com.mirko.customeitem.view.ItemGroup
android:id="@+id/ig_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:drawable_left="@drawable/menu_home"
app:drawable_right="@drawable/arrow_right"
app:title="首页" />
<com.mirko.customeitem.view.ItemGroup
android:id="@+id/ig_soft"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:drawable_left="@drawable/menu_about"
app:drawable_right="@drawable/arrow_right"
app:line_height="1"
app:title="软件介绍" />
<com.mirko.customeitem.view.ItemGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:drawable_left="@drawable/menu_cart"
app:drawable_right="@drawable/arrow_right"
app:line_height="1"
app:title="购物车" />
<com.mirko.customeitem.view.ItemGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:drawable_left="@drawable/menu_conditions"
app:title="相关条款" />
<com.mirko.customeitem.view.ItemGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:drawable_left="@drawable/menu_push_message"
app:title="推送服务" />
<com.mirko.customeitem.view.ItemGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:drawable_left="@drawable/menu_settings"
app:line_height="0"
app:title="设置" />