Android自定义UI实战(基础篇1)---组合控件封装

在实际开发过程中,我们会碰到许多这种界面

Android自定义UI实战(基础篇1)---组合控件封装_第1张图片

下面来介绍怎样封装成为一个通用的控件

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="设置" />

你可能感兴趣的:(Android自定义UI实战)