Android - 自定义控件(四)

在一个应用中,很多页面的titlebar布局都是类似的,比如,最左侧一个返回箭头,中间是title,右侧要么是文字要么是图标要么是空白,实现方式一般有以下几种:

1、分别针对每一种可能用到的布局写一个布局文件,然后根据需要在activity的布局中采用include的方式将title布局引入进来

2、类似Android - 自定义控件(三)的方式写一个自定义的titlebar

3、采用自定义属性的方式

本篇文章通过自定义属性来完成一个自定义的titlebar,假设该titlebar的左侧固定为图片,中间固定为文本,而右侧为图片或者文本。则完成步骤如下:

一、首先在res/values文件目录下创建一个attrs.xml文件。然后在attrs.xml文件中完成对属性的定义,代码片段如下:

 

<?xml version="1.0" encoding="utf-8"?>
<resources>
     <!-- TitleBar -->
    <declare-styleable name="TitleBar">
        <attr name="background" format="reference|color" />
        <attr name="title" format="string" localization="suggested" />
        <attr name="leftImg" format="reference" />
        <attr name="rightImg" format="reference" />
        <attr name="rightText" format="reference" />
    </declare-styleable>
</resources>

 

<attr>标签的format属性值代表属性的类型,这个类型值一共有10种,分别是:reference,float,color,dimension,boolean,string,enum,integer,fraction,flag。常用的基本上只有reference,float,color,dimension,boolean,string,enum这7种。枚举类型定义的格式为:

<attr name="flowDirection" format="enum">
    <enum name="leftToRight" value="0" />
    <enum name="topDown" value="1" />
    <enum name="rightToLeft" value="2" />
    <enum name="bottomUp" value="3" />
</attr>

在attrs.xml文件中的<declare-styleable>标签的name属性的值,按照惯例我们都是写成自定义控件类的名字。一个同名的<attr>在attrs.xml中只可以定义一次。

二、编写自定义的类,在构造方法中获取我们设置的值(即在XML文件中引入自定义控件时,设置的属性),代码:

public class TitleBar extends LinearLayout {
	
	private RelativeLayout rlTitle;
	/** 左按钮 */
	private View btnleft;
	/** 右按钮 */
	private View btnRight;
	/** 标题文本 */
	private String title;
	/** 标题控件 */
	private TextView tvTitle;

	public TitleBar(Context context) {
		super(context);
	}

	public TitleBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);
	}

	public TitleBar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context, attrs);
	}
	
	@SuppressLint("NewApi")
	private void init(Context context, AttributeSet attrs) {
		setOrientation(LinearLayout.HORIZONTAL);
		TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitleBar);
		CharSequence csTitle = a.getText(R.styleable.TitleBar_title);
		Drawable bgDrawable = a.getDrawable(R.styleable.TitleBar_background);
		int leftImg = a.getResourceId(R.styleable.TitleBar_leftImg, -1);
		int rightImg = a.getResourceId(R.styleable.TitleBar_rightImg, -1);
		CharSequence rightText = a.getText(R.styleable.TitleBar_rightText);
		View view = null;
		int type = 0;//0:右侧按钮模式;1:右侧文本模式
		if (rightText != null && !"".equals(rightText)) {
			type = 1;
			view = LayoutInflater.from(getContext()).inflate(R.layout.layout_top_right_text, this, true);
		} else {
			view = LayoutInflater.from(getContext()).inflate(R.layout.layout_top, this, true);
		}
		rlTitle = (RelativeLayout) view.findViewById(R.id.rl_title);
		tvTitle = (TextView) view.findViewById(R.id.tv_title);
		ImageButton ib_left = (ImageButton) view.findViewById(R.id.btn_left);
		btnleft = ib_left;
		if (csTitle != null && !"".equals(csTitle)) {
			tvTitle.setText(csTitle);
		}
		rlTitle.setVisibility(View.VISIBLE);
		if (leftImg != -1) {
			ib_left.setVisibility(View.VISIBLE);
			ib_left.setImageResource(leftImg);
		} else {
			ib_left.setVisibility(View.INVISIBLE);
		}
		if (type == 0) {//0:右侧按钮模式
			ImageButton ib_right = (ImageButton) view.findViewById(R.id.btn_right);
			if (rightImg != -1) {
				ib_right.setVisibility(View.VISIBLE);
				ib_right.setImageResource(rightImg);
			} else {
				ib_right.setVisibility(View.INVISIBLE);
			}
			btnRight = ib_right;
		} else {//1:右侧文本模式
			Button btn_right = (Button) view.findViewById(R.id.btn_right);
			if (rightText != null && !"".equals(rightText)) {
				btn_right.setText(rightText);
				btn_right.setVisibility(View.VISIBLE);
			} else {
				btn_right.setVisibility(View.INVISIBLE);
			}
			btnRight = btn_right;
		}
		if (bgDrawable != null) {
			if (Build.VERSION.SDK_INT >= 16) {
				rlTitle.setBackground(bgDrawable);
			} else {
				rlTitle.setBackgroundDrawable(bgDrawable);
			}
		} else {//缺省颜色
			rlTitle.setBackgroundColor(Color.parseColor("#365663"));
		}
		a.recycle();
	}
	
	public View getBtnleft() {
		return btnleft;
	}
	
	public View getBtnRight() {
		return btnRight;
	}
		
	public String getTitle() {
		return title;
	}
	
	/**
	 * 设置标题文本
	 * @param title
	 */
	public void setTitle(int title) {
		setTitle(getResources().getString(title));
	}
	
	/**
	 * 设置标题文本
	 * @param title
	 */
	public void setTitle(String title) {
		this.title = title;
		if (title == null || "".equals(title)) {
			rlTitle.setVisibility(View.GONE);
		} else {
			rlTitle.setVisibility(View.VISIBLE);
			tvTitle.setText(title);
		}
		invalidate();
	}
}

需要注意的是,TypedArray对象在使用完毕后一定要调用recycle()方法。

三、在布局文件中引入自定义的titlebar:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:hwgt="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.hwgttitlebar.MainActivity" >
    <com.example.hwgttitlebar.view.TitleBar
		android:id="@+id/titleBar"
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		hwgt:leftImg="@drawable/ic_arrow"
		hwgt:title="@string/hwgt_title"
		hwgt:rightText="@string/hwgt_right_text"/>
    
</RelativeLayout>

需要注意的是,要在使用自定义属性的布局文件中声明命名空间:

xmlns:hwgt="http://schemas.android.com/apk/res-auto"

以上三步就搞定了,下边是其他涉及到的代码:

layout_top_right_text.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/rl_title"
	android:layout_width="match_parent"
	android:layout_height="54dp">
	<ImageButton
		android:id="@+id/btn_left"
		android:layout_width="54dp"
		android:layout_height="match_parent"
		android:layout_alignParentLeft="true"
		android:src="@drawable/ic_arrow"
		android:visibility="visible"
		android:background="@drawable/sel_bg_btn_title"/>
	<TextView
		android:id="@+id/tv_title"
		android:layout_width="wrap_content"
		android:layout_height="match_parent"
		android:layout_centerVertical="true"
		android:layout_toRightOf="@id/btn_left"
		android:layout_toLeftOf="@+id/btn_right"
		android:paddingLeft="5dp"
		android:paddingRight="5dp"
		android:gravity="center"
		android:text=""
		android:textColor="@android:color/white"
		android:textSize="20dp"
		android:singleLine="true"
		android:maxLines="1"
		android:ellipsize="none"/>
	<Button
		android:id="@id/btn_right"
		android:layout_width="wrap_content"
		android:layout_height="match_parent"
		android:minWidth="54dp"
		android:text=""
		android:textColor="@android:color/white"
		android:textSize="15dp"
		android:paddingLeft="4dp"
		android:paddingRight="12dp"
		android:layout_alignParentRight="true"
		android:background="@drawable/sel_bg_btn_title"/>
</RelativeLayout>

layout_top.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/rl_title"
	android:layout_width="match_parent"
	android:layout_height="54dp">
	<ImageButton
		android:id="@+id/btn_left"
		android:layout_width="54dp"
		android:layout_height="match_parent"
		android:layout_alignParentLeft="true"
		android:src="@drawable/ic_arrow"
		android:visibility="visible"/>
	<TextView
		android:id="@+id/tv_title"
		android:layout_width="wrap_content"
		android:layout_height="match_parent"
		android:layout_centerVertical="true"
		android:layout_toRightOf="@id/btn_left"
		android:layout_toLeftOf="@+id/btn_right"
		android:paddingLeft="5dp"
		android:paddingRight="5dp"
		android:gravity="center"
		android:text=""
		android:textColor="@android:color/white"
		android:textSize="20dp"
		android:singleLine="true"
		android:maxLines="1"
		android:ellipsize="none"/>
	<ImageButton
		android:id="@id/btn_right"
		android:layout_width="54dp"
		android:layout_height="match_parent"
		android:layout_alignParentRight="true"
		android:background="@drawable/sel_bg_btn_title"
		android:visibility="invisible"/>
	<ImageView
		android:id="@+id/iv_logo"
		android:layout_width="54dp"
		android:layout_height="match_parent"
		android:layout_alignParentRight="true"
		android:paddingLeft="2dp"
		android:paddingRight="2dp"
		android:scaleType="fitCenter"
		android:visibility="gone"/>
</RelativeLayout>

drawable下的sel_bg_btn_title.xml:

<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
	<item android:drawable="@drawable/bg_btn_title_press" android:state_pressed="true" />
	<item android:drawable="@android:color/darker_gray"/>
</selector>

bg_btn_title_press.xml:

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
    android:shape="rectangle">
    <solid android:color="#33ffffff"/>
</shape>

  

 

 

posted on 2016-04-22 11:42  快乐的码农  阅读(301)  评论(0)    收藏  举报