自定义滑动开关按钮
继承已有View实现自定义View
主要步骤:
1.自定义类继承View 构造方法(注意每个的作用)
2.重写onMeasure方法,指定控件大小 测量view的大小 onMeasure方法
3.确定view的位置,view自身有一些建议权,决定权在父view手中. onLayuot();
4.重写onDraw方法,绘制控件的内容 onDraw方法
5.重写onTouchEvent方法,对touch事件进行解析 onTouchEvent方法
当监听了onTouchEvent与onClick方法时,滑动控件也会执行onClick方法,所以需要对这个进行处理:
处理方式见代码:就是在控件上滑动的时候定义个标记,让执行onClick方法的时候判断这个标记
使用到的图片如下:
效果:将右边这图作为左边按钮的背景图片
显示的功能:既可以点击也可以滑动
MainActivity.java :只是用来显示界面
MyButton.java :监听事件都在本类,没有和MainActivity相关联(缺陷)
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.os.SystemClock; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; public class MyButton extends View implements OnClickListener{ private Bitmap backgroundBitmap;//开关的背景图片 private Bitmap slideBtn;//可以滑动的图片 private Paint paint;//画笔,用来画图片 //滑动按钮在画布上的左边界,也就是根据滑动按钮的在画布上的位置来做出开与关的效果 private float slideBtn_left; private boolean currentstart=false;//滑动按钮的当前状态,false为关,true为开 /** * 在代码里面创建对象的时候,调用此构造方法 */ public MyButton(Context context) { super(context); } /** * 在布局文件中声明的view,创建时由系统自动调用此构造方法 * @param context * @param attrs */ public MyButton(Context context, AttributeSet attrs) { super(context, attrs); //初始化图片 backgroundBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.switch_background); slideBtn=BitmapFactory.decodeResource(getResources(), R.drawable.slide_button); //初始化画笔 paint=new Paint(); paint.setAntiAlias(true);//打开抗锯齿 //为该视图设置监听事件 setOnClickListener(this); } /** * 测量尺寸时的回调方法 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //设置当前view的大小 确定下面onDraw方法中画布的大小,所以这里不管布局文件中怎么设置长宽,这里都设置为了背景图片的宽高 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); } /** * 绘制内容 */ @Override protected void onDraw(Canvas canvas) { //画出backgroundBitmap这个图片,(0,0)代表在这个画布的左上角开始画 canvas.drawBitmap(backgroundBitmap, 0, 0, paint); /*绘制 可滑动的按钮, 在画布上的坐标为:(slideBtn_left, 0)=(X,Y) * 即:当slideBtn_left等于0的时候,按钮的左上角就在画布的左上角位置,就把开挡住了,显示当前为关的状态 * 当slideBtn_left=背景图片的宽-按钮的宽 ,代表按钮的左上角位置画在画布的(slideBtn_left, 0) */ canvas.drawBitmap(slideBtn, slideBtn_left, 0, paint); } @Override public void onClick(View v) { if(!ismove){//如果之前没拖动,就执行单击事件 if(currentstart){//开 slideBtn_left=0; }else{ slideBtn_left=backgroundBitmap.getWidth()-slideBtn.getWidth(); } System.out.println("响应onClick事件"); currentstart=!currentstart; invalidate();//刷新视图,会调用onDraw方法 } } //实现滑动的效果 private int moveX;//记录移动后的位置,因为有时候移动一次停一下(没松开)再继续移动 private int firstX;//记录第一次按下的位置 private boolean ismove=false;//之前是否拖动了,false表示没拖动 //onTouchEvent执行后会执行onClick方法,所以需要一个标记,来确定执不执行单击事件 @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event);//不调用就会把onClick屏蔽掉 switch (event.getAction()) { case MotionEvent.ACTION_DOWN://按下 firstX=moveX=(int) event.getX(); ismove=false;//复位,使得下一次可以判断,必须在此复位 break; case MotionEvent.ACTION_MOVE://移动 int move=(int) event.getX()-moveX;//移动的距离 slideBtn_left=slideBtn_left+move; moveX=(int) event.getX();//将移动的一次的位置记录下来 if(slideBtn_left>backgroundBitmap.getWidth()-slideBtn.getWidth()){ slideBtn_left=backgroundBitmap.getWidth()-slideBtn.getWidth(); }else if(slideBtn_left<0){ slideBtn_left=0; } ismove=true;//标记为拖动了,所以松开的时候只会执行触摸的UP事件,不会去执行单击事件,因为在单击事件中进行了判断 break; case MotionEvent.ACTION_UP://抬起 if(ismove){//如果拖动了就执行触摸事件 if(event.getX()<backgroundBitmap.getWidth()/2){ slideBtn_left=0;//因为图片这个位置是关, 注意这里的event.getX是手指抬起的那点的坐标 currentstart=false;//标记为关的状态 }else{ slideBtn_left=backgroundBitmap.getWidth()-slideBtn.getWidth(); currentstart=true;//标记为开的状态 } System.out.println("响应onTouchEvent事件"); break; } } invalidate();//刷新视图 return true; } }
布局文件activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 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=".MainActivity" > <!-- 因为继承了View,所以可以使用View的所有属性,所以就可以使用下面的属性 --> <com.example.zdykg.MyButton android:id="@+id/my_but" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true"/> </RelativeLayout>
效果如下:
系统的滑动控件:Switch
Android 自定义 Switch 控件外观 (缺陷,不能控制宽高)
比较灵活的第三方滑动控件:
https://github.com/kyleduo/SwitchButton
使用可参考:https://www.cnblogs.com/tianzhijiexian/p/4231509.html
设置监听