UI界面——自定义组件

开发过程经常需要我们控件。除了使用系统控件之外,我们也需要自定义控件实现特定的效果。

通常的自定义控件的步骤为:

  1. 自定义控件类继承View类
  2. 重写onMeasure方法。
  3. 从写onDraw方法
  4. 重写onToucheEvent方法

同时如果为了扩展起见,我们 希1、 在attrs.xml文件中声明属性,由属性名:name和格式:format。如:<declare-styleable name=”MyToggleBtn”>
<attr name=”current_state” format=”boolean” />
</declare-styleable>
望支持自定义属性。通过参考系统自带控件,一般可划分为三步:

首先,在attrs.xml文件中声明属性,由属性名:name和格式:format。如:


<declare-styleablename=”MyToggleBtn”>


<attr name=”current_state”format=”boolean” />


</declare-styleable>


fromat常用的类型


reference

引用

color

颜色

boolean

布尔值

dimension

尺寸

float

浮点值

integer

整型值

string

字符串

enum

枚举类型


 

其次,在布局文件中使用新属性,使用之前必须先声明命名空间,如:xmlns:ldd="http://schemas.android.com/apk/res/com.example.togglebutton"(xmlns:自定义名称=http://schemas.android.com/apk/res/包名)

最后在自定义view的构造方法中,通过解析attributeSet对象获得所需的属性值。

下面是完整的代码:

package com.example.togglebutton;


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;


public class MyToggle extends View implements View.OnClickListener{
	private int lastX;
	private int firstX;
	private boolean isDrag=false;
	private int backgroundId;
	private Bitmap backgroundBp;
	private Bitmap slideBp;
	private float slide_left;
	private Paint paint;
	private boolean currState=false;
	private int slideId;
	public MyToggle(Context context) {
		super(context);
	}
	
	public MyToggle(Context context,AttributeSet attrs) {
		super(context, attrs);
		//实际可用类型
		TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.MyBtn);
		int taCount=ta.getIndexCount();
		for(int i=0;i<taCount;i++){
			int itId=ta.getIndex(i);
			switch (itId) {
			case R.styleable.MyBtn_my_background:
				backgroundId = ta.getResourceId(itId, -1);
				backgroundBp=BitmapFactory.decodeResource(this.getResources(), backgroundId);
				break;
			case R.styleable.MyBtn_my_slide_btn:
				slideId = ta.getResourceId(itId, -1);
				slideBp=BitmapFactory.decodeResource(this.getResources(), slideId);
				break;
			case R.styleable.MyBtn_cur_state:
				currState=ta.getBoolean(itId,false);
				break;
			}
		}
		initView();
	}
	/**
	 * 
	 * @Title: initView
	 * @Description: 初始化
	 */
	private void initView() {
		paint=new Paint();
		paint.setAntiAlias(true);//开启抗锯齿,画笔平滑过渡
		
		setOnClickListener(this);
		flushState();
	}

	@Override
	/**
	 *1、 测量尺寸的回调方法
	 */
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		//设置view的大小
		setMeasuredDimension(backgroundBp.getWidth(), backgroundBp.getHeight());
	}
	
	@Override
	/**
	 * 2、确定位置的时候的回调
	 * 自定义View没用
	 */
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);
	}

	@Override
	/**
	 *3、 绘画 方法,初始化或者刷新时自动调用
	 */
	protected void onDraw(Canvas canvas) {
		canvas.drawBitmap(backgroundBp, 0, 0, paint);
		canvas.drawBitmap(slideBp, slide_left, 0, paint);
	}

	@Override
	/**
	 * 为控件添加点击事件
	 */
	public void onClick(View v) {
		if(!isDrag){//是否屏蔽click
		currState=!currState;
		flushState();
		}
		
	}

	@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) > 6) {
				isDrag = true;
			}
			int dis = (int) (event.getX() - lastX);
			lastX = (int) event.getX();
			slide_left = slide_left + dis;
			break;
		case MotionEvent.ACTION_UP:
			if (isDrag) {
				// 判断当前状态,并自动补全
				int max = backgroundBp.getWidth() - slideBp.getWidth();

				if (slide_left > max / 2) {
					currState = true;
				} else {
					currState = false;
				}
				flushState();
			}

			break;
		}
		flushView();
		return true;
	}
	/**
	 * @Title: flushView
	 * @Description: 刷新视图
	 */
	private void flushView() {
		int max=backgroundBp.getWidth()-slideBp.getWidth();
		slide_left=slide_left>0?slide_left:0;//控制左边界
		slide_left=slide_left<max?slide_left:max;//控制右边界
		invalidate();
	}

	/**
	 * 
	 * @Title: flushState
	 * @Description: 刷新当前开关状态
	 */
	private void flushState() {
		if(currState){
			slide_left=backgroundBp.getWidth()-slideBp.getWidth();
		}else{
			slide_left=0;
		}
		flushView();
	}
}

自定义属性文件:

<resources>
   <declare-styleable name="MyBtn">
       <attr name="my_background" format="reference" />
       <attr name="my_slide_btn" format="reference" />
       <attr name="cur_state" format="boolean" />
    </declare-styleable>
</resources>

控件使用:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ldd="http://schemas.android.com/apk/res/com.example.togglebutton"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
    <com.example.togglebutton.MyToggle 
        android:id="@+id/my_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        ldd:my_background="@drawable/switch_background"
        ldd:my_slide_btn="@drawable/slide_button"
        ldd:cur_state="false"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        Test="hello"
        />

</RelativeLayout>


最终效果是开关按钮。

总之,自定义控件参考系统自带控件的写法即可。完整 示例项目:http://download.csdn.net/download/dd864140130/8222541


UI界面——自定义组件_第1张图片





你可能感兴趣的:(自定义,按钮,控件,界面,开关)