package cn.flyaudio.android;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class SlipButton extends View implements OnTouchListener {
private String TAG = "SlipButton";
private boolean onSlip = false;//记录用户是否在滑动的变量
private float downX, nowX, oldX;//按下时的x,当前的x
private Bitmap slip_btn_down, slip_btn_thumb, slip_btn_up, slip_btn_bg;//图片
private Rect slip_thumb_rect;//矩形
public SlipButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init(context, attrs);
}
public SlipButton(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init(context, attrs);
}
//初始化
private void init(Context context, AttributeSet attrs) {
// 跟values/attrs.xml里面定义的属性绑定
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlipButton);
slip_btn_down = drawableToBitmap(a.getDrawable(R.styleable.SlipButton_slip_btn_down)); //按下图片
slip_btn_thumb = drawableToBitmap(a.getDrawable(R.styleable.SlipButton_slip_btn_thumb));//滑动图片
slip_btn_up = drawableToBitmap(a.getDrawable(R.styleable.SlipButton_slip_btn_up)); //为按下的图片
//返回一个绑定结束的信号给资源
a.recycle();
slip_btn_bg = slip_btn_up;
slip_thumb_rect = new Rect(0, 0, slip_btn_bg.getWidth(), slip_btn_bg.getHeight());
setOnTouchListener(this);// 设置监听器
}
//绘制部分
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = new Paint();
canvas.drawBitmap(slip_btn_bg, 0, 0, paint);
if(!onSlip){//在没有滑动的情况下
if(nowX <= slip_btn_bg.getWidth()/2){
canvas.save();//记录原来的canvas状态
canvas.clipRect(slip_thumb_rect);
canvas.drawBitmap(slip_btn_thumb,slip_btn_bg.getWidth()-slip_btn_thumb.getWidth(),0,paint);
canvas.restore();//恢复canvas状态
}else if(nowX > slip_btn_bg.getWidth()/2){
canvas.save();//记录原来的canvas状态
canvas.clipRect(slip_thumb_rect);
canvas.drawBitmap(slip_btn_thumb,0, 0,paint);
canvas.restore();//恢复canvas状态
}
}else if(onSlip){//在滑动的情况下
canvas.save();//记录原来的canvas状态
canvas.clipRect(slip_thumb_rect);
if(nowX < oldX){//向左滑的时候
if((nowX-oldX) > slip_btn_bg.getWidth()-slip_btn_thumb.getWidth()){
canvas.drawBitmap(slip_btn_thumb,nowX-oldX, 0,paint);
}else{
canvas.drawBitmap(slip_btn_thumb,slip_btn_bg.getWidth()-slip_btn_thumb.getWidth(), 0,paint);
}
}else if(nowX > oldX ){//向右滑的时候
if((slip_btn_bg.getWidth()-slip_btn_thumb.getWidth()) +(nowX - oldX) <0){
canvas.drawBitmap(slip_btn_thumb,(slip_btn_bg.getWidth()-slip_btn_thumb.getWidth()) +(nowX - oldX), 0,paint);
}else{
canvas.drawBitmap(slip_btn_thumb,0, 0,paint);
}
}
canvas.restore();//恢复canvas状态
}
}
//逻辑控制部分
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch(event.getAction())//根据动作来执行代码
{
case MotionEvent.ACTION_MOVE://滑动
if(event.getX()>slip_btn_bg.getWidth()||event.getY()>slip_btn_bg.getHeight() || event.getX()<0 || event.getY()<0)
return false;
slip_btn_bg = slip_btn_down;
nowX = event.getX(); //得到的是触摸点相对于按钮的坐标
onSlip = true;
break;
case MotionEvent.ACTION_DOWN://按下
if(event.getX()>slip_btn_bg.getWidth()||event.getY()>slip_btn_bg.getHeight() || event.getX()<0 || event.getY()<0)
return false;
slip_btn_bg = slip_btn_down;
downX = event.getX();
nowX = downX;
oldX = downX;
break;
case MotionEvent.ACTION_UP://松开
slip_btn_bg = slip_btn_up;
onSlip = false;
break;
default:
}
invalidate();//重画控件
return true;
}
//将drawable转换为bitmap
public static Bitmap drawableToBitmap(Drawable drawable) {
// 取 drawable 的长宽
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
// 取 drawable 的颜色格式
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565;
// 建立对应 bitmap
Bitmap bitmap = Bitmap.createBitmap(w, h, config);
// 建立对应 bitmap 的画布
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
// 把 drawable 内容画到画布中
drawable.draw(canvas);
return bitmap;
}
}
今天在公司写了一个自定义控件,主要是一个可以实现左右滑动的自定义按钮。
里面的涉及到的一些知识点主要有:
1、自定义控件的属性的设置;
2、自定义控件怎么继承View这个父类来写控件;
首先是自定义控件属性的设置:
- 先在values文件夹下写一个xml文件,文件名为:attrs.xml
-
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="SlipButton"><!-- 控件名称--> <!-- 属性名称,类型--> <attr name="slip_btn_down" format="reference"/> <attr name="slip_btn_thumb" format="reference"/> <attr name="slip_btn_up" format="reference"/> </declare-styleable> </resources>
-
控件属性与XML定义绑定: // 跟values/attrs.xml里面定义的属性绑定 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlipButton); slip_btn_down = drawableToBitmap(a.getDrawable(R.styleable.SlipButton_slip_btn_down)); //按下图片 slip_btn_thumb = drawableToBitmap(a.getDrawable(R.styleable.SlipButton_slip_btn_thumb));//滑动图片 slip_btn_up = drawableToBitmap(a.getDrawable(R.styleable.SlipButton_slip_btn_up)); //为按下的图片 //返回一个绑定结束的信号给资源 a.recycle();
-
//将drawable转换为bitmap public static Bitmap drawableToBitmap(Drawable drawable) { // 取 drawable 的长宽 int w = drawable.getIntrinsicWidth(); int h = drawable.getIntrinsicHeight(); // 取 drawable 的颜色格式 Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; // 建立对应 bitmap Bitmap bitmap = Bitmap.createBitmap(w, h, config); // 建立对应 bitmap 的画布 Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, w, h); // 把 drawable 内容画到画布中 drawable.draw(canvas); return bitmap;
TypedArray其实就是一个存放资源的Array,首先从上下文中获取到
-
R.styleable.SlipButton这个属性资源的资源数组。 attrs是构造函数传进来,应该就是对应attrs.xml文件。 a.getString(R.styleable.SlipButton_slip_btn_thumb);这句代码就是获取attrs.xml中定义的属性,并将这个属 性的值传给本控件的slip_btn_thumb.最后,返回一个绑定结束的信号给资源:a.recycle();绑定结束。 在xml中对控件赋初始值: <?xml version="1.0" encoding="utf-8"?> <!-- 一定要声明命名空间 --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:flyaudio="http://schemas.android.com/apk/res/cn.flyaudio.android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <cn.flyaudio.android.SlipButton android:id = "@+id/slipBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft = "100sp" flyaudio:slip_btn_thumb="@drawable/slip_btn_thumb" flyaudio:slip_btn_down="@drawable/slip_btn_down" flyaudio:slip_btn_up="@drawable/slip_btn_up" /> </LinearLayout> 红色部分首先声明命名空间。命名空间为fsms.路径是http://schemas.android.com/apk/res/ 这一部分是不变的, 后面接的是R的路径:cn.flyaudio.android。 然后在自定义控件的xml描述中就可以这样使用flyaudio:slip_btn_thumb="@drawable/slip_btn_thumb" 。这样就实现了自定义控件的初始化赋值。