自定义控件如同系统控件:自定义控件,画空间图片,定义空间属性,构造监听器。

  android的基本控件很难满足用户的需求,因此有时候用户需要根据美工设置的一些图片来自定义一些控件,不多说,现在介绍一下,自定义一个开关控件的流程,让大家更了解控件的工作原理:

1、首先构建一个控件的类,继承view,这时候需要覆写view的构造方法。同时需要把美工美化好的图片拖到drawable目录下。在控件初始化的时候需要加载进美工的图片即:背景bg和开关滑动钮swicher。注意加载图片时候R.drawable时候有2个注意别选错了,否则找不到图片的id。

2、android的控件都是通过view下的Ondraw()方法画上去的,因此要覆写view的Oncreate方法将bg和swicher画上去。画画需要画纸和笔,因此在初始化的时候构建一支笔,画板系统提供,即参数里的canvas.里面的参数分别是图、上,左的坐标和笔。因此我们要设定的就是画的位置就是上左的坐标即可。

3、这时候我们可以在xml文件里可以添加这个控件看看效果了,注意添加空间时候一定加上包名和类名(不要带上class如:<com.example.togglebutton.ui.MytoggleButton即可,同时在最上面加上控件的命名空间:复制android的,并将android改成这个程序的包名即可。注意的是,默认下控件大小是屏幕的长宽,因此需要调用onMeasure()方法测量宽高和setMeasuredDimension()重新设定宽高。

4、为了让空间可以拖动,就必须覆写view的onTouchEvent()方法,注意所有的触摸事件的方法都是由这个方法来处理的,然后监听:落下、滑动、离开这3个动作(想更复杂的也可以监听别的事件),通过打印发现只能监听到“落下”的事件,原来这个方法默认是系统处理的,若想用户自己处理就必须将return surper.onTouchEvent()修改成return true;(ps:当你的控件继承其他的具体控件时候,若继承的空间有自己的监听器接口时候,这里就不能改为true,并且已经可监听到,因为继承的控件已经覆写了View的OntouchEvent事件了,若该为true时候继承的操作就失效了)。

5、设定事件处理,我们根据ondraw方法画图,里设定坐标时候将左设定为类的成员变量,上为0,因此当我们改变left的值,然后调用invalidate()刷新操作调用ondraw()方法来重新画图即可。

6、设定控件的属性,这里就添加一个状态state当作事例,首先在values里创建一个xml文件,然后在xml文件里声明、定义属性atrrs。如果大家不记得就可以参考安装的sdk目录下android自带属性的定义:sdkplatformsandroid-19data esvaluesattrs.xml。并且在构造方法:public MytoggleButton(Context context, AttributeSet attrs)里解析属性,好在配置文件中使用属性,并且里面设置默认属性值。

7、在类里给出设定state和得到state的函数,并将state作为函数的成员变量。

8、给空间设定监听事件,这里就定义一个监听state发生改变的接口,在接口里声明state发生变化的方法。然后将接口作为类的成员变量,为类设定一个设置监听器的函数,将接口作为参数,因此设置监听器必须实现这个接口,然后把实现额接口复制给类成员变量。

9在ontouchEvent()的up里先判断状态是否改变,若改变就利用实例化了接口的类来调用接口的onchange方法就完成了状态放生改变的监听事件。

下面给出完整的demo:

main.xml文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myview="http://schemas.android.com/apk/res/com.example.togglebutton.ui"
    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.togglebutton.MainActivity$PlaceholderFragment"
    android:background="#ffff00"
     >

    <com.example.togglebutton.ui.MytoggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        myview:state="true"
        android:id="@+id/togglebutton"
       />
    <TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/text"
      	android:layout_centerVertical="true"
      	android:layout_centerHorizontal="true"
        
        />

</RelativeLayout>

  values 下的属性定义文件atrrs.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="myview">
   <attr name="state" format="boolean" />
     </declare-styleable>
</resources>

  开关控件类的定义

package com.example.togglebutton.ui;

import com.example.togglebutton.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.text.Editable.Factory;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MytoggleButton extends View {
	private Context context; 
	private Bitmap bg;
	private Bitmap sw;
	private Paint paint;
	private  int maxleft;
	private int left;
	private  boolean state;
	
	private OnMytoggleButtonStateChangeLitener onMytoggleButtonStateChangeLitener;
	
	public void setOnMytoggleButtonStateChangeLitener(OnMytoggleButtonStateChangeLitener l)
	{
		onMytoggleButtonStateChangeLitener=l;
	}
	
	
	public MytoggleButton(Context context) {
		super(context);
		this.context=context;
		init();
	}

	//这里是解析属性的AttributeSet attrs,可以在配置文件中使用这些属性
	public MytoggleButton(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context=context;	
		init();
		//解析属性
		String namespace="http://schemas.android.com/apk/res/com.example.togglebutton";
		state=attrs.getAttributeBooleanValue(namespace, "state", true);//默认为关
		if(state==false)
			left=0;
		else
			left=maxleft;
		
	}

	public MytoggleButton(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		this.context=context;	
		init();
		}
	//初始化
	public void init()
	{
		 paint=new Paint();
		 sw=BitmapFactory.decodeResource(getResources(), R.drawable.slide_button_background);
		 bg=BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
		 maxleft=bg.getWidth()-sw.getWidth();
	}

	public void setState(boolean state)
	{
		if(state=true)
			{
			left=maxleft;
			state=true;
			}
		else 
			{
			state=false;
			left=0;
			}
		invalidate();
	}
	public boolean getState()
	{
		return state;
	}
	
	@Override//这是空间开始创建时会运行一次
	protected void onDraw(Canvas canvas) {
		
		canvas.drawBitmap(bg, 0, 0, paint);
		canvas.drawBitmap(sw, left, 0,paint);
		super.onDraw(canvas);
		
	}

	
	
	
	@Override//限制空间高宽
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		setMeasuredDimension(bg.getWidth(), bg.getHeight());
	}

	int startX=0;
	int currentX=0;
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		
	
		
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			startX=(int) event.getX();
			System.out.println("down"+state);
			break;
		case MotionEvent.ACTION_MOVE:
			currentX=(int) event.getX();
			int d=currentX-startX;
			left=d+left;
			if(left>=maxleft)
				left=maxleft;
			else if(left<=0)
				left=0;
			System.out.println("move"+state);
			break;
		case MotionEvent.ACTION_UP:
			boolean stateOlder=state;
			System.out.println("up"+state);
			if(left>maxleft/2)
			{
				left=maxleft;
				state=true;
				}
			else
			{
				left=0;
				state=false;
				}
			
			if(state!=stateOlder&&onMytoggleButtonStateChangeLitener!=null)
				onMytoggleButtonStateChangeLitener.stateChange(getState());
			
			break;

		default:
			break;
		}
	
		invalidate();//刷新画图,调用空间的ondrow()方法
		return true;//super.onTouchEvent(event);
	}
	
	
}

  activity文件:

public class MainActivity extends Activity {

	private MytoggleButton togglebutton;
	private TextView tx;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        togglebutton=(MytoggleButton) findViewById(R.id.togglebutton);
        tx=(TextView) findViewById(R.id.text);
        tx.setText("State:"+(togglebutton.getState()?"开":"关"));
        togglebutton.setOnMytoggleButtonStateChangeLitener(new OnMytoggleButtonStateChangeLitener(){

			@Override
			public void stateChange(boolean state) {
				 tx.setText("State:"+(togglebutton.getState()?"开":"关"));
			}
        }
        		);
        
    }
}

  

原文地址:https://www.cnblogs.com/bokeofzp/p/4768760.html