为android自定义View控件添加自定义的属性

主要步骤:

1、在attrs.xml文件中声明属性,有属性名:name和格式:format 。如:

   

<declare-styleable name="MyToggleBtn"> 
        <attr  name="current_state" format="boolean"/> 
   </declare-styleable>

2、在布局文件中使用新属性,使用之前必须先声明命名空间,如:xmlns:heima="http://schemas.android.com/apk/res/com.itheima.mytogglebtn"

3、在自定义view的构造方法当中,通过解析 AttributeSet 对象,获得所需要的属性值。


一、在attrs.xml文件中声明属性,如:

<declare-styleable name="MyToggleBtn">    //声名属性集的名称,即这些属性是属于哪个控件的。
        <attr name="current_state" format="boolean"/>    //声名属性 current_state  格式为 boolean 类型
        <attr name="slide_button" format="reference"/>    //声名属性 slide_button  格式为 reference 类型
   </declare-styleable>


所有的format类型,详见注1:

二、在布局文件中使用:在使用之前必须声名命名空间,xmlns:heima="http://schemas.android.com/apk/res/com.itheima.mytogglebtn"

  说明:xmlns 是XMLname space 的缩写;

        heima 可为任意写符

        http://schemas.android.com/apk/res/  此为android固定格式;

        com.itheima.mytogglebtn  此应用的包名,如manifest配置文件中一致。

   布局文件:

   <com.itheima.mytogglebtn.MyToggleButton

       xmlns:heima="http://schemas.android.com/apk/res/com.itheima.mytogglebtn"

       android:layout_width="wrap_content"

       android:layout_height="wrap_content"

       heima:slide_button="@drawable/slide_button" />

三、在代码中对属性进行解析,主要代码:

TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MyToggleBtn);  // 由attrs 获得TypeArray

注1:

format 常用类型

reference  引用

color  颜色

boolean  布尔值

dimension  尺寸值

float  浮点值

integer  整型值

string  字符串

enum  布尔值


附一完整的自定义控件实现

public class MyToggleButton extends View implements OnClickListener{

	/**
	 * 做为背景的图片
	 */
	private Bitmap backgroundBitmap;
	/**
	 * 可以滑动的图片
	 */
	private Bitmap slideBtn;
	private Paint paint;
	/**
	 * 滑动按钮的左边届
	 */
	private float slideBtn_left;
	/**
	 * 背景图的资源ID
	 */
	private int backgroundId;
	/**
	 * 滑动图片的资源ID
	 */
	private int slideBtnId;

	/**
	 * 在代码里面创建对象的时候,使用此构造方法
	 */
	public MyToggleButton(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	/**
	 * 在布局文件中声名的view,创建时由系统自动调用。
	 * @param context	上下文对象
	 * @param attrs		属性集
	 */
	public MyToggleButton(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		//无命名空间测试
		
		String testAttrs = attrs.getAttributeValue(null, "testAttrs");
		
		System.out.println("testAttrs===:"+testAttrs);
		
		
		//获得自定义的属性
		TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyToggleBtn);
		
		int N = ta.getIndexCount();
		for (int i = 0; i < N; i++) {
			/*
			 * 获得某个属性的ID值
			 */
			int itemId = ta.getIndex(i);
			switch (itemId) {
			case R.styleable.MyToggleBtn_curr_state:
				currState = ta.getBoolean(itemId, false);
				
				break;
			case R.styleable.MyToggleBtn_my_background:
				backgroundId = ta.getResourceId(itemId, -1);
				if(backgroundId == -1){
					throw new RuntimeException("请设置背景图片");
				}
				backgroundBitmap = BitmapFactory.decodeResource(getResources(), backgroundId);
				
				break;
			case R.styleable.MyToggleBtn_my_slide_btn:
				slideBtnId = ta.getResourceId(itemId, -1);
				slideBtn = BitmapFactory.decodeResource(getResources(), slideBtnId);
				
				break;

			default:
				break;
			}
			
		}
		
		
		initView();
	}
	
	/**
	 * 初始化
	 */
	private void initView() {
		//初始化图片
//		backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
//		slideBtn = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
		
		
		//初始化 画笔
		paint = new Paint();
		paint.setAntiAlias(true); // 打开抗矩齿
		
		
		//添加onclick事件监听
		setOnClickListener(this);
		
		flushState();
	}

	/*
	 * view 对象显示的屏幕上,有几个重要步骤:
	 * 1、构造方法 创建 对象。
	 * 2、测量view的大小。	onMeasure(int,int);
	 * 3、确定view的位置 ,view自身有一些建议权,决定权在 父view手中。  onLayout();
	 * 4、绘制 view 的内容 。 onDraw(Canvas)
	 */
	
	@Override
	/**
	 * 测量尺寸时的回调方法 
	 */
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		
		/**
		 * 设置当前view的大小
		 * width  :view的宽度
		 * height :view的高度   (单位:像素)
		 */
		setMeasuredDimension(backgroundBitmap.getWidth(),backgroundBitmap.getHeight());
	}

	//确定位置的时候调用此方法
	//自定义view的时候,作用不大
//	@Override
//	protected void onLayout(boolean changed, int left, int top, int right,
//			int bottom) {
//		super.onLayout(changed, left, top, right, bottom);
//	}
	
	/**
	 * 当前开关的状态
	 *  true 为开
	 */
	private boolean currState = false;
	
	@Override
	/**
	 * 绘制当前view的内容
	 */
	protected void onDraw(Canvas canvas) {
//		super.onDraw(canvas);
		
		// 绘制 背景
		/*
		 * backgroundBitmap	要绘制的图片
		 * left	图片的左边届
		 * top	图片的上边届
		 * paint 绘制图片要使用的画笔
		 */
		canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
		
		//绘制 可滑动的按钮
		canvas.drawBitmap(slideBtn, slideBtn_left, 0, paint);
	}

	/**
	 * 判断是否发生拖动,
	 * 如果拖动了,就不再响应 onclick 事件
	 * 
	 */
	private boolean isDrag = false;
	@Override
	/**
	 * onclick 事件在View.onTouchEvent 中被解析。
	 * 系统对onclick 事件的解析,过于简陋,只要有down 事件  up 事件,系统即认为 发生了click 事件
	 * 
	 */
	public void onClick(View v) {
		/*
		 * 如果没有拖动,才执行改变状态的动作
		 */
		if(!isDrag){
			currState = !currState;
			flushState();
		}
	}


	
	/**
	 * down 事件时的x值
	 */
	private int firstX;
	/**
	 * touch 事件的上一个x值
	 */
	private int lastX;
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);
		
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			firstX = lastX =(int) event.getX();
			isDrag = false;
			
			break;
		case MotionEvent.ACTION_MOVE:
			
			//判断是否发生拖动
			if(Math.abs(event.getX()-firstX)>5){
				isDrag = true;
			}
			
			//计算 手指在屏幕上移动的距离
			int dis = (int) (event.getX() - lastX);
			
			//将本次的位置 设置给lastX
			lastX = (int) event.getX();
			
			//根据手指移动的距离,改变slideBtn_left 的值
			slideBtn_left = slideBtn_left+dis;
			break;
		case MotionEvent.ACTION_UP:
			
			//在发生拖动的情况下,根据最后的位置,判断当前开关的状态
			if (isDrag) {

				int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth(); // slideBtn
																					// 左边届最大值
				/*
				 * 根据 slideBtn_left 判断,当前应是什么状态
				 */
				if (slideBtn_left > maxLeft / 2) { // 此时应为 打开的状态
					currState = true;
				} else {
					currState = false;
				}

				flushState();
			}
			break;
		}
		
		flushView();
		
		return true; 
	}

	/**
	 * 刷新当前状态
	 */
	private void flushState() {
		if(currState){
			slideBtn_left = backgroundBitmap.getWidth()-slideBtn.getWidth();
		}else{
			slideBtn_left = 0;
		}
		
		flushView(); 
	}
	
	/**
	 * 刷新当前视力
	 */
	private void flushView() {
		/*
		 * 对 slideBtn_left  的值进行判断 ,确保其在合理的位置 即       0<=slideBtn_left <=  maxLeft
		 * 
		 */
		
		int maxLeft = backgroundBitmap.getWidth()-slideBtn.getWidth();	//	slideBtn 左边届最大值
		
		//确保 slideBtn_left >= 0
		slideBtn_left = (slideBtn_left>0)?slideBtn_left:0;
		
		//确保 slideBtn_left <=maxLeft
		slideBtn_left = (slideBtn_left<maxLeft)?slideBtn_left:maxLeft;
		
		/*
		 * 刷新当前视图  导致 执行onDraw执行
		 */
		invalidate();
	}

}


整理自相关教程
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值