Android开发自定义UI组件

Android开发自定义UI组件

一些复用的UI组件,可以通过设置模板复用,接口回调等方法提高开发效率,降低代码耦合度。


自定义组件大概分为3步:

  1、自定义标签属性

  2、定义组件类

  3、在XML界面布局使用自定义标签

下面举例实现一个TopBar和一个GridItem的自定义组件。

这是项目目录结构


一、自定义标签属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    //TopBar标签属性定义
    <declare-styleable name="TopBar">
        <attr name="titleTopBar"    format="string"></attr>
        <attr name="titleTextSize"  format="dimension"></attr>
        <attr name="titleTextColor" format="color"></attr>
        <attr name="leftTextColor"  format="color"></attr>
        <attr name="leftBackground" format="reference|color"></attr>
        <attr name="leftText"       format="string"></attr>
        <attr name="rightTextColor" format="color"></attr>
        <attr name="rightBackground" format=" reference|color"></attr>
        <attr name="rightText"      format="string"></attr>
    </declare-styleable>
    //GridItem标签属性定义
    <declare-styleable name="GridItem">
        <attr name="titlegrid" format="string"></attr>
        <attr name="content"   format="string"></attr>
        <attr name="image"     format="reference"></attr>
    </declare-styleable>

</resources>

format 参数值:
1. reference:参考某一资源ID
2. color:颜色值
3. boolean:布尔值
4. dimension:尺寸值
5. float:浮点值
6. integer:整型值
7. string:字符串
8. fraction:百分数
9. enum:枚举值
//enum举例  属性定义:  
< declare -styleable name = "UI名称" >  
    <attr name = "orientation" >  
        <enum name = "horizontal" value = "0" />  
        <enum name = "vertical" value = "1" />  
    </attr>                        
</ declare -styleable>  
10. flag:位或运算
  

二、定义组件类

    TopBar组件类

public class TopBar extends RelativeLayout {

	//左边Button,中间标题,右边Button
	private Button leftBtn, rightBtn;
	private TextView tvTitle;

	private int leftTextColor;//左边Button字体颜色
	private Drawable leftBackground;//左边Button背景色
	private String leftText;//左边button文本

	private int rightTextColor;
	private Drawable rightBackground;
	private String rightText;

	private float titleTextSize;//标题字体大小
	private int titleTextColor;//标题字体颜色
	private String title;//标题内容
	private LayoutParams leftParams, rightParams, titleParams;
	private topBarClickListener listener;

	/**
	 * 接口回调,实现按钮监听模板
	 */
	public interface topBarClickListener {
		public void leftClick();//点击左边按钮监听

		public void rightClick();//点击右边按钮监听
	}

	public void setOnTopBarClickListener(topBarClickListener listener) {
		this.listener = listener;
	}

	public TopBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		//用TypedArray获得TopBar属性回传的值
		TypedArray ta = context.obtainStyledAttributes(attrs,
				R.styleable.TopBar);
        //左边按钮属性值
		leftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0);
		leftBackground = ta.getDrawable(R.styleable.TopBar_leftBackground);
		leftText = ta.getString(R.styleable.TopBar_leftText);
        //右边按钮属性值
		rightTextColor = ta.getColor(R.styleable.TopBar_rightTextColor, 0);
		rightBackground = ta.getDrawable(R.styleable.TopBar_rightBackground);
		rightText = ta.getString(R.styleable.TopBar_rightText);
        //中间标题属性值
		title = ta.getString(R.styleable.TopBar_titleTopBar);
		titleTextColor = ta.getColor(R.styleable.TopBar_titleTextColor, 0);
		titleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize, 0);
		// 回收,避免浪费资源
		ta.recycle();
        //此处是创建控件对象,通过LayoutParams设置控件属性,也可使用XML界面布局代码创建
		leftBtn = new Button(context);
		rightBtn = new Button(context);
		tvTitle = new TextView(context);

		leftBtn.setTextColor(leftTextColor);
		leftBtn.setBackground(leftBackground);
		leftBtn.setText(leftText);

		rightBtn.setTextColor(rightTextColor);
		rightBtn.setBackground(rightBackground);
		rightBtn.setText(rightText);

		tvTitle.setText(title);
		tvTitle.setTextColor(titleTextColor);
		tvTitle.setTextSize(titleTextSize);
		tvTitle.setGravity(Gravity.CENTER);

		setBackgroundColor(0x66E93EFF);

		leftParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		leftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
		addView(leftBtn, leftParams);

		rightParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		rightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
		addView(rightBtn, rightParams);

		titleParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.MATCH_PARENT);
		titleParams.addRule(RelativeLayout.CENTER_IN_PARENT);
		addView(tvTitle, titleParams);

		leftBtn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				listener.leftClick();
			}
		});
		rightBtn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				listener.rightClick();
			}
		});
	}

	/**
	 * 定义左边Button是否可见
	 */
	public void setLeftButtonVisiable(boolean flag) {
		if (flag) {
			leftBtn.setVisibility(View.VISIBLE);
		} else {
			leftBtn.setVisibility(View.GONE);
		}
	}

	/**
	 * 定义右边Button是否可见
	 */
	public void setRightButtonVisiable(boolean flag) {
		if (flag) {
			rightBtn.setVisibility(View.VISIBLE);
		} else {
			rightBtn.setVisibility(View.GONE);
		}
	}

	/**
	 * 设置左边Button背景
	 */
	public void setLeftBackground(int resid) {
		leftBtn.setBackgroundResource(resid);
	}

	/**
	 * 设置右边Button背景
	 */
	public void setRightBackground(int resid) {
		rightBtn.setBackgroundResource(resid);
	}

}


GridItem组件类

public class GridItem extends LinearLayout {

	private TextView tvGridTitle, tvGridContent;
	private ImageView ivGridIcon;

	private View gridView;

	private String title;
	private String content;
	private Drawable imageResId;

	public GridItem(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		TypedArray ta = context.obtainStyledAttributes(attrs,
				R.styleable.GridItem);

		gridView = LayoutInflater.from(context).inflate(R.layout.grid_item,
				this, true);

		tvGridTitle = (TextView) gridView.findViewById(R.id.tvGridTitle);
		tvGridContent = (TextView) gridView.findViewById(R.id.tvGridContent);
		ivGridIcon = (ImageView) gridView.findViewById(R.id.ivGridIcon);

		// 获取自定义属性值
		title = ta.getString(R.styleable.GridItem_titlegrid);
		content = ta.getString(R.styleable.GridItem_content);
		imageResId = ta.getDrawable(R.styleable.GridItem_image);

		// 回收一下,避免资源浪费
		ta.recycle();

		tvGridTitle.setText(title);
		tvGridContent.setText(content);
		ivGridIcon.setImageDrawable(imageResId);
	}
}
GridItem布局文件grid_item.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"
    android:padding="3dp"
    android:paddingLeft="6dp" >

    <TextView
        android:id="@+id/tvGridTitle"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:textSize="10sp" />

    <TextView
        android:id="@+id/tvGridContent"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:textSize="10sp" />

    <ImageView
        android:id="@+id/ivGridIcon"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_gravity="right"
        android:layout_weight="2"
        android:scaleType="fitCenter"
        android:scaleX="0.8"
        android:scaleY="0.8" />

</LinearLayout>
自定义组件的布局,一般是由简单的组件组合而成,组合成新的自定义组件,可以创建一个单独的布局文件进行定义。


三、在XML界面布局使用自定义标签

activity_main.xml布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    <span style="color:#ff0000;">xmlns:app="http://schemas.android.com/apk/res/com.example.topbar"</span>
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.topbar.view.TopBar
        android:id="@+id/topbar"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        app:leftTextColor="#fff"
        app:rightText="设置"
        app:rightTextColor="#fff"
        app:titleTextColor="#fff"
        app:titleTextSize="13sp"
        app:titleTopBar="自定义标题" >
    </com.example.topbar.view.TopBar>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/topbar"
        android:layout_margin="10dp"
        android:orientation="horizontal" >

        <com.example.topbar.view.GridItem
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#66FF0000"
            app:content="安卓开发"
            app:image="@drawable/grid_icon1"
            app:titlegrid="Android" />

        <com.example.topbar.view.GridItem
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginLeft="10dp"
            android:background="#660000FF"
            app:content="编程语言"
            app:image="@drawable/grid_icon2"
            app:titlegrid="C++" />

        <com.example.topbar.view.GridItem
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="#66AA7700"
            app:content="服务器"
            android:layout_marginLeft="10dp"
            app:image="@drawable/grid_icon3"
            app:titlegrid="Linux" />


        <com.example.topbar.view.GridItem
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginLeft="10dp"
            android:background="#66228B22"
            app:content="苹果开发"
            app:image="@drawable/grid_icon4"
            app:titlegrid="Ios" />
    </LinearLayout>

</RelativeLayout>
<h4><span style="color:#ff0000;">首先重点是声明组件的命名空间,作用相当于类中引用包名。</span></h4>

xmlns:app="http://schemas.android.com/apk/res/<span style="color:#ff0000;">com.example.topbar</span>

与系统的命名空间比较:

系统:xmlns:android="http://schemas.android.com/apk/res/<span style="color:#ff0000;">android</span>

res/后面的包名不同。

在AndroidStudio中可以设置为这样:

xmlns:custom="http://schemas.android.com/apk/<span style="color:#ff0000;">res-auto</span>

四、效果图如下





  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值