自定义控件如同系统控件:自定义控件,画空间图片,定义空间属性,构造监听器。
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自带属性的定义:sdk\platforms\android-19\data\res\values\attrs.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()?"开":"关"));
}
}
);
}
}
浙公网安备 33010602011771号