自定义view控件 TypedArray

我们在扣扣  微信等界面 都可以看到如下图 红色方框里面的   中间是标题  两边是按钮


如果很多页面都需要类似的功能 ,我们则可以自己制作一个这样的控件,然后就可以引用,省去好多麻烦。

下面则是如何制作这样的控件


一 、首先在values文件下 新建一个attrs.xml文件,其代码如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="Topbar">
        <attr name="leftTextColor" format="color" />
        <attr name="leftBackground" format="reference|color" />
        <attr name="leftText" format="string" />
        
        <attr name="title" format="string" />
        <attr name="titleTextSize" format="dimension" />
        <attr name="titleTextColor" format="color" />
        
        <attr name="rightTextColor" format="color" />
        <attr name="rightBackground" format="reference|color" />
        <attr name="rightText" format="string" />
    </declare-styleable>

</resources>
其中:<declare-styleable name="Topbar">    declare-styleable 是指自定义意思,我们自己定义新的控件时候则需要用declare-styleable  来声明(除了自带的),name ="Topbar"  指的是 控件的名字是Topbar。

        <attr name="leftTextColor" format="color" />
        <attr name="leftBackground" format="reference|color" />
        <attr name="leftText" format="string" />

里面的 name="leftTextColor" 表示的是属性的名字是leftTextColor  ,就像android:textcolor 一样;format="color" 是指格式是color类型的 

这里的自定义属性的format,可以有很多种:

  • reference
  • string
  • color
  • dimension
  • boolean
  • integer
  • float
  • fraction
  • enum
  • flag

二、创建Topbar.java类 代码如下:

package com.example.myview;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;

<strong>public class Topbar extends RelativeLayout</strong> {

	private Button leftButton, rightButton;
	private TextView tvTitle;

	private int leftTextColor;
	private Drawable leftBackground;
	private String leftText;

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

	private float titleTextSize;
	private int titleTextColor;
	private String title;

	private LayoutParams titlepParams, leftpParams, rightpParams;
	

	@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
	@SuppressLint("NewApi")
	<strong>public Topbar(final Context context, AttributeSet attrs) {
		super(context, attrs);
		TypedArray ta = context.obtainStyledAttributes(attrs,
				R.styleable.Topbar);</strong>
		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);

		titleTextSize = ta.getDimension(R.styleable.Topbar_titleTextSize, 0);
		titleTextColor = ta.getColor(R.styleable.Topbar_titleTextColor, 0);
		title = ta.getString(R.styleable.Topbar_title);

		<strong>ta.recycle();</strong>
		
		leftButton = new Button(context);
		rightButton = new Button(context);
		tvTitle = new TextView(context);

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

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

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

		setBackgroundColor(0xfff59563);

		leftpParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		leftpParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);

		addView(leftButton, leftpParams);

		rightpParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		rightpParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);

		addView(rightButton, rightpParams);

		titlepParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		titlepParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);

		addView(tvTitle, titlepParams);

	}
}
关于 TypedArray  其api如下

方法摘要
 booleangetBoolean(int index, boolean defValue) 
          Retrieve the boolean value for the attribute at index.
 intgetColor(int index, int defValue) 
          Retrieve the color value for the attribute at index.
 ColorStateListgetColorStateList(int index) 
          Retrieve the ColorStateList for the attribute at index.
 floatgetDimension(int index, float defValue) 
          Retrieve a dimensional unit attribute at index.
 intgetDimensionPixelOffset(int index, int defValue) 
          Retrieve a dimensional unit attribute at index for use as an offset in raw pixels.
 intgetDimensionPixelSize(int index, int defValue) 
          Retrieve a dimensional unit attribute at index for use as a size in raw pixels.
 DrawablegetDrawable(int index) 
          Retrieve the Drawable for the attribute at index.
 floatgetFloat(int index, float defValue) 
          Retrieve the float value for the attribute at index.
 floatgetFraction(int index, int base, int pbase, float defValue) 
          Retrieve a fractional unit attribute at index.
 intgetIndex(int at) 
          Return an index in the array that has data.
 intgetIndexCount() 
          Return the number of indices in the array that actually have data.
 intgetInt(int index, int defValue) 
          Retrieve the integer value for the attribute at index.
 intgetInteger(int index, int defValue) 
          Retrieve the integer value for the attribute at index.
 intgetLayoutDimension(int index, int defValue) 
          Special version of getDimensionPixelSize(int, int) for retrieving ViewGroup's layout_width and layout_height attributes.
 intgetLayoutDimension(int index, String name) 
          Special version of getDimensionPixelSize(int, int) for retrieving ViewGroup's layout_width and layout_height attributes.
 StringgetNonResourceString(int index) 
          Retrieve the string value for the attribute at index, but only if that string comes from an immediate value in an XML file.
 StringgetPositionDescription() 
          Returns a message about the parser state suitable for printing error messages.
 intgetResourceId(int index, int defValue) 
          Retrieve the resource identifier for the attribute at index.
 ResourcesgetResources() 
          Return the Resources object this array was loaded from.
 StringgetString(int index) 
          Retrieve the string value for the attribute at index.
 CharSequencegetText(int index) 
          Retrieve the styled string value for the attribute at index.
 CharSequence[]getTextArray(int index) 
          Retrieve the CharSequence[] for the attribute at index.
 booleangetValue(int index, TypedValue outValue) 
          Retrieve the raw TypedValue for the attribute at index.
 booleanhasValue(int index) 
          Determines whether there is an attribute at index.
 intlength() 
          Return the number of values in this array.
 TypedValuepeekValue(int index) 
          Retrieve the raw TypedValue for the attribute at index and return a temporary object holding its data.
 voidrecycle() 
          Give back a previously retrieved StyledAttributes, for later re-use.
 StringtoString() 
          Returns a string containing a concise, human-readable description of this object.

下面说说AttributeSet与TypedArray在自定义控件中的作用:

AttributeSet的作用就是在控件进行初始化的时候,解析布局文件中该控件的属性(key eg:background)与该值(value eg:@drawable/icon)的信息封装在AttributeSet中,传递给该控件(View)的构造函数。对于非Android自带的属性,在View类中处理时是无法识别的,因此需要我们自己解析。所以这就要用到另外一个类TypedArray。在AttributeSet中我们有属性名称,有属性值,但是控件如何知道哪个属性代表什么意思呢?这个工作就由TypedArray来做了。TypedArray对象封装了/values/attrs.xml中的styleable里定义的每个属性的类型信息,通过TypedArray我们就可以知道AttributeSet中封装的值到底是干什么的了,从而可以对这些数据进行应用。

AttributeSet就相当于一盒糖,TypedArray就相当于这盒糖上的标签说明,告诉用户每个糖的口味等。这盒糖有什么口味是由用户自己的styleable文件里面的内容来决定的。 

TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.Topbar);  第二个参数  R.styleable.Topbar 就是attrs.xml里面的控件。


 leftTextColor = ta.getColor(R.styleable.Topbar_leftTextColor, 0);  为左边按钮的文字设置颜色,当我们输入R.stylable.  的时候 就会有代码提示Topbar_leftTextColor,指的是attrs.xml文件里面 Topbar控件的leftTextColor属性  。第二个参数是defValue,代码中的意思是如果第一个参数没有找到对应的资源,则返回defValue设置的值。

leftBackground = ta.getDrawable(R.styleable.Topbar_leftBackground);  为左边按钮设置背景图片


leftText = ta.getString(R.styleable.Topbar_leftText);  为左边按钮设置名字


ta.recycle(); 调用结束后务必调用recycle()方法,否则这次的设定会对下次的使用造成影响  。

leftButton = new Button(context);
rightButton = new Button(context);
tvTitle = new TextView(context);
上面进行实例化 

leftButton.setTextColor(leftTextColor); 为左边按钮添加字体颜色
leftButton.setBackground(leftBackground); 为左边按钮添加背景图片
leftButton.setText(leftText);为左边按钮添加名字


setBackgroundColor(0xfff59563); 为整体添加背景颜色


leftpParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
为左边按钮设置属性 类似于  android:layout_width="wrap_content"    android:layout_height="wrap_content"  
leftpParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
为左边按钮增加规则 类似于   android:layout_alignParentLeft="true"
addView(leftButton, leftpParams);

把左边按钮添加到视图中。

三、在activity_main.xml 文件中引入自作的控件

其代码如下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   <strong> xmlns:custom="http://schemas.android.com/apk/res/com.example.myview"</strong>
    xmlns:tools="http://schemas.android.com/tools"
    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="com.example.myview.MainActivity" >
   
    <strong><com.example.myview.Topbar</strong>   
        android:id="@+id/topbar"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        <strong> custom:leftBackground="@drawable/ic_launcher"
        custom:leftText="Back"
        custom:leftTextColor="#ffffff"
        custom:rightBackground="@drawable/ic_launcher"
        custom:rightText="More"
        custom:rightTextColor="#ffffff"       
        custom:title="自定义标题"
        custom:titleTextColor="#000000"
        custom:titleTextSize="12sp" /></strong>

</RelativeLayout>

我们需要在布局文件里面添加一些代码 

 1.如果用eclipse 编辑代码的话添加   xmlns:custom="http://schemas.android.com/apk/res/com.example.myview"  custom 是命名空间 可以自己命名 ,com.example.myview 则是文件的具体包名。

2.如果用as编辑代码则 需要添加代码是     xmlns:custom="http://schemas.android.com/apk/res-auto


custom:leftBackground="@drawable/ic_launcher"
左边按钮的背景图片  (我采用的是系统的自带的,大家可以网上找关于按钮的背景图片)  

custom:leftText="Back"
 
左边按钮的 名字为  "Back"     

  custom:leftTextColor="#ffffff"
 
左边按钮的名字的颜色  

custom:title="自定义标题"
   
中间标题的名字为"自定义标题" 

custom:titleTextColor="#000000"
 
中间标题的颜色     

custom:titleTextSize="12sp" 

标题的字体大小

写完代码 在视图中可能看不到效果图 但是没关系 ,运行下 可以看到效果如下图



四、为按钮添加点击事件
如果只有按钮没有点击功能,那么岂不是白费力气

在Topbar.xml里面添加如下代码

private TopbarClickListener listener;

	public interface TopbarClickListener {

		<strong>public void backClick();

		public void morekClick();</strong>
	};

	public void setOnTopbarClickListener(TopbarClickListener listener) {
		this.listener = listener;
	}

leftButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {

				<strong>listener.backClick();</strong>
			}
		});

		rightButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				<strong>listener.morekClick()</strong>;

			}
		});

在MainActivity.java 里面代码如下

package com.example.myview;



import com.example.myview.Topbar.TopbarClickListener;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Topbar topbar = (Topbar) findViewById(R.id.topbar);
		topbar.setOnTopbarClickListener(new TopbarClickListener() {
			
			@Override
			public void morekClick() {
				 Toast.makeText(MainActivity.this, "hello", Toast.LENGTH_SHORT).show();
				
			}
			
			@Override
			public void backClick() {
				// TODO Auto-generated method stub
				 Toast.makeText(MainActivity.this, "JAVA", Toast.LENGTH_SHORT).show();
			}
		});
		
		//<span style="font-family: monospace; white-space: pre; background-color: rgb(240, 240, 240);">topbar.leftbuttonIsVisiable(false);//隐藏左边按钮</span>
	}

	

}

五、完善

有时候我们需要隐藏一个按钮  不让其显示,以隐藏左边按钮为例

在Topbar.xml添加一个方法 

public void leftbuttonIsVisiable(boolean bool) {
		if (bool) {
			leftButton.setVisibility(View.VISIBLE);

		} else {
			leftButton.setVisibility(View.GONE);
		}
	}

通过判断传进参数是真假 来隐藏按钮


在MainActivity.java 需要加一句代码

	topbar.leftbuttonIsVisiable(false);//隐藏左边按钮


Topbar.xml里面完整代码如下 

package com.example.myview;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class Topbar extends RelativeLayout {

	private Button leftButton, rightButton;
	private TextView tvTitle;

	private int leftTextColor;
	private Drawable leftBackground;
	private String leftText;

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

	private float titleTextSize;
	private int titleTextColor;
	private String title;

	private LayoutParams titlepParams, leftpParams, rightpParams;
	private TopbarClickListener listener;

	public interface TopbarClickListener {

		public void backClick();

		public void morekClick();
	};

	public void setOnTopbarClickListener(TopbarClickListener listener) {
		this.listener = listener;
	}

	@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
	@SuppressLint("NewApi")
	public Topbar(final Context context, AttributeSet attrs) {
		super(context, attrs);
		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);

		titleTextSize = ta.getDimension(R.styleable.Topbar_titleTextSize, 0);
		titleTextColor = ta.getColor(R.styleable.Topbar_titleTextColor, 0);
		title = ta.getString(R.styleable.Topbar_title);

		ta.recycle();
		
		leftButton = new Button(context);
		rightButton = new Button(context);
		tvTitle = new TextView(context);

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

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

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

		setBackgroundColor(0xfff59563);

		leftpParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		leftpParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);

		addView(leftButton, leftpParams);

		rightpParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		rightpParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);

		addView(rightButton, rightpParams);

		titlepParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		titlepParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);

		addView(tvTitle, titlepParams);

		leftButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {

				listener.backClick();
			}
		});

		rightButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				listener.morekClick();

			}
		});

	}

	public void leftbuttonIsVisiable(boolean bool) {
		if (bool) {
			leftButton.setVisibility(View.VISIBLE);

		} else {
			leftButton.setVisibility(View.GONE);
		}
	}

}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值