1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Android自定义View-滑动解锁按钮

Android自定义View-滑动解锁按钮

时间:2019-12-10 05:18:23

相关推荐

Android自定义View-滑动解锁按钮

Android自定义View-滑动解锁按钮

写在前面一、实现的思路二、先上成品图三、自定义属性四、使用五、具体实现

写在前面

最近由于项目需求,需要有一个类似苹果的滑动解锁控件,抱着万事不求人的学习态度,这种时候肯定是要自己肝出一个这样的控件了,以下带来实现的思路与具体过程

一、实现的思路

个人觉得自定义View肯定要整理自己的实现思路,只有思路清晰明确了,才能够顺利的实现自己所需的功能,以下浅淡一下,实现滑动解锁的具体思路:

1、滑动解锁方面,肻定要有一个按钮与文本,按钮只需要实现点击滑过的功能,所以这边我继承了TextView免去文本的操作,其实继承Button也是可以的,看个人的选择2、实现文本之后,还要有按钮,想了下利用drawCircle实现不难,外边的弧可以用drawRoundRect实现,剩下的就是控制文本、按钮还有弧之间的距离了3、实现之后上述功能后,就是要做点击操作了,这边可以重写onTouchEvent,来实现这个滑动的过程

思路整理完之后好像没什么难度,开始撸代码

二、先上成品图

按钮以图片形式

按钮默认模式

三、自定义属性

<declare-styleable name="ButtonSliding"><!-- 弧的颜色--><attr name="boundColor" format="color"></attr><!-- 文本的颜色--><attr name="mtextColor" format="color"></attr><!-- 按钮是选择图片还是默认的颜色按钮形式,默认是颜色,设置true之后需设置btnSrc--><attr name="typeColor" format="boolean"/><!-- 按钮的图片或者颜色,只有在typeColor设置为true时有效--><attr name="btnSrc" format="reference|color"></attr></declare-styleable>

四、使用

<com.example.test.Widget.ButtonSlidingandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="滑动进入会议"android:textSize="24sp"android:visibility="visible"app:boundColor="@color/colorSkyBlue"app:mtextColor="#FFC107"app:typeColor="true"app:btnSrc="@mipmap/icon"app:layout_constraintBottom_toTopOf="@+id/btnTest"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"/>

五、具体实现

package com.example.test.Widget;import android.animation.ValueAnimator;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.Rect;import android.graphics.RectF;import android.util.AttributeSet;import android.util.TypedValue;import android.view.MotionEvent;import android.view.animation.BounceInterpolator;import com.example.test.R;/*** 滑动进入** @author chen*/public class ButtonSliding extends androidx.appcompat.widget.AppCompatTextView {/*** 文本颜色画笔*/private Paint paintText;/*** 背景弧画笔*/private Paint paintRect;/*** 按钮画笔*/private Paint paintCircle;private Context context;/*** 背景弧颜色*/private int boundColor = Color.RED;/*** 文本弧颜色*/private int mTextColor = Color.BLACK;private Bitmap bitmap;/*** 按钮背景*/private int drawableId;private boolean isColorSrc = true;public ButtonSliding(Context context, AttributeSet attrs) {super(context, attrs);this.context = context;TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ButtonSliding);boundColor = typedArray.getColor(R.styleable.ButtonSliding_boundColor,boundColor);mTextColor = typedArray.getColor(R.styleable.ButtonSliding_boundColor,mTextColor);drawableId = typedArray.getResourceId(R.styleable.ButtonSliding_btnSrc, 0);isColorSrc = typedArray.getBoolean(R.styleable.ButtonSliding_typeColor, isColorSrc);if (isColorSrc) {} else {if(drawableId == 0)throw new IllegalArgumentException("资源设置null");bitmap = BitmapFactory.decodeResource(getResources(), drawableId);}typedArray.recycle();init();}/*** 初始化画笔*/private void init() {paintText = new Paint();paintText.setDither(true);paintText.setAntiAlias(true);paintText.setStyle(Paint.Style.FILL);paintText.setTextSize(getTextSize());paintText.setColor(mTextColor);paintRect = new Paint();paintRect.setDither(true);paintRect.setAntiAlias(true);paintRect.setColor(boundColor);paintRect.setStyle(Paint.Style.STROKE);paintRect.setStrokeWidth(pxToDp(2));paintCircle = new Paint();paintCircle.setDither(true);paintCircle.setAntiAlias(true);paintCircle.setStyle(Paint.Style.FILL);paintCircle.setStrokeWidth(pxToDp(2));}/*** 测量处理,默认情况*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//获取宽高的模式int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);//指定宽高的大小int width = MeasureSpec.getSize(widthMeasureSpec);int height = MeasureSpec.getSize(heightMeasureSpec);//如果宽高设置为wrap_content时,刚默认为300if (widthMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.AT_MOST) {height = 200;width = height * 4;}//如果宽高不一致时,则以高为标准if (width != height) {width = height * 4;}setMeasuredDimension(width, height);}@Overrideprotected void onDraw(Canvas canvas) {drawCircle(canvas);drawText(canvas);// drawButton(canvas);if (isColorSrc) {drawButton(canvas);} else {drawBitmap(canvas);}}/*** 按钮X(left)与Y(top)的值*/private int btnBitmapX;private int btnBitmapY;/*** 按钮X(right)与Y(bottom)的值*/private int btnBitmapX2;private int btnBitmapY2;/*** 绘制图片的按钮* @param canvas*/private void drawBitmap(Canvas canvas) {RectF rectF = new RectF(btnBitmapX, btnBitmapY, btnBitmapX2, btnBitmapY2);Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());canvas.drawBitmap(bitmap, rect, rectF, paintCircle);}/*** 缩放图片* @param bitmap* @param newWidth* @param newHeight* @return*/public Bitmap getNewBitmap(Bitmap bitmap, int newWidth, int newHeight) {// 获得图片的宽高.int width = bitmap.getWidth();int height = bitmap.getHeight();// 计算缩放比例.float scaleWidth = ((float) newWidth) / width;float scaleHeight = ((float) newHeight) / height;// 取得想要缩放的matrix参数.Matrix matrix = new Matrix();matrix.postScale(scaleWidth, scaleHeight);// 得到新的图片.Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);return newBitmap;}/*** 创建新的圆角图片* @param bitmap* @param px* @return*/public Bitmap makeRoundCorner(Bitmap bitmap, int px){int width = bitmap.getWidth();int height = bitmap.getHeight();Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(output);int color = 0xff424242;Paint paint = new Paint();Rect rect = new Rect(0, 0, width, height);RectF rectF = new RectF(rect);paint.setAntiAlias(true);canvas.drawARGB(0, 0, 0, 0);paint.setColor(color);canvas.drawRoundRect(rectF, px, px, paint);paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));canvas.drawBitmap(bitmap, rect, rect, paint);return output;}/*** 绘制按钮** @param canvas*/private void drawButton(Canvas canvas) {canvas.drawCircle(btnX, btnY, btnRadus, paintCircle);}/*** 绘制背景弧** @param canvas*/private void drawCircle(Canvas canvas) {RectF rectF = new RectF(x - x, y - y, x + x, y + y);canvas.drawRoundRect(rectF, 100, 100, paintRect);}private float pxToDp(int value) {return TypedValue.applyDimension(PLEX_UNIT_DIP, value, context.getResources().getDisplayMetrics());}/*** 按钮半径*/private int btnRadus;/*** 绘制文本** @param canvas*/private void drawText(Canvas canvas) {String text = (String) getText();//获取文本的宽高Rect rect = new Rect();paintText.getTextBounds(text.trim(), 0, text.trim().length(), rect);int dx = getWidth() / 2 - rect.width() / 2 + btnRadus;Paint.FontMetrics fontMetrics = paintText.getFontMetrics();//基线float baseline = getHeight() / 2 + (fontMetrics.top - fontMetrics.bottom) / 2 - fontMetrics.top;//绘制文本canvas.drawText(text, dx, baseline, paintText);}/*** 中心点*/private int y;private int x;/*** 按钮中心点*/private int btnX;private int btnY;/*** 按钮与背景弧的间隙*/private int btnBound = 10;/*** 背景的图片*/private int bitmapRadus;@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {//数值太多选择在测量时初始化,在构造函数时有些数值拿不到,draw刷新时又会被重新赋值,所以选择在此初始化//初始化中心点x = (right - left) / 2;y = (bottom - top) / 2;//初始化中心点btnRadus = (y + y) / 2 - btnBound;//按钮的X,YbtnX = btnRadus + btnBound;btnY = y;//按钮图片的X,YbtnBitmapX = btnBound;btnBitmapY = btnBound;btnBitmapX2 = btnRadus + btnRadus + btnBound;btnBitmapY2 = btnRadus + btnRadus + btnBound;//按钮图片与弧的间隙bitmapRadus = btnBitmapX2 - btnBitmapX;if(!isColorSrc){bitmap = getNewBitmap(bitmap, btnRadus + btnRadus, btnRadus + btnRadus);bitmap = makeRoundCorner(bitmap,100);}super.onLayout(changed, left, top, right, bottom);}@Overridepublic boolean onTouchEvent(MotionEvent event) {int X = (int)event.getX();switch (event.getAction()) {//手指移动时case MotionEvent.ACTION_MOVE:if(isColorSrc){btnX = (X) ;//到达右端一定距离时调用接口if (btnX >= x + x - btnBound - btnRadus - 5) {buttonSildingEvent.onOver();}//如果超出控件范围则不调用刷新if (btnX >= x + x - btnBound - btnRadus || btnX <= btnRadus + btnBound)break;//如果在控件范围则不调用刷新if (btnX <= x + x - btnRadus - btnBound && btnX >= btnRadus + btnBound)postInvalidate();}else {btnBitmapX2 = (X);//同上if (btnBitmapX2 >= x + x || btnBitmapX2 <= btnRadus + btnBound) {break;}//同上if (btnBitmapX2 >= x + x - btnBound - btnRadus - 5) {buttonSildingEvent.onOver();}//同上if (btnBitmapX2 <= x + x - btnRadus - btnBound && btnBitmapX2 >= btnRadus + btnBound)postInvalidate();}break;//手指抬起时case MotionEvent.ACTION_UP:if(isColorSrc){btnX = (X);//如果超出控件边界,则给定默认值if (btnX > x + x - btnRadus)btnX = x + x - btnRadus;//如果超出控件边界,则给定默认值if (btnX < btnRadus + btnBound)btnX = btnRadus + btnBound;reset(btnX);}else {btnBitmapX2 = (X);btnBitmapX = (X) - bitmapRadus;//同上if (btnBitmapX2 > x + x - btnRadus)btnBitmapX2 = x + x - btnRadus;//同上if (btnBitmapX2 < btnRadus + btnBound)btnBitmapX2 = btnRadus + btnBound;reset(btnBitmapX2);}break;}return true;}/*** 松手回弹*/private void reset(int start) {ValueAnimator valueAnimator = ValueAnimator.ofInt(start, btnRadus + btnBound);valueAnimator.setDuration(1000);valueAnimator.setInterpolator(new BounceInterpolator());valueAnimator.start();valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {if(isColorSrc){//X的值,Y不用管btnX = (int) animation.getAnimatedValue();}else {//图片是由Rect决定绘制图片的位置,所以要赋值X与X2btnBitmapX2 = (int) animation.getAnimatedValue();btnBitmapX = (int) animation.getAnimatedValue() - bitmapRadus;if(btnBitmapX <= 0){btnBitmapX = btnBound;btnBitmapX2 = btnRadus + btnRadus + btnBound;}}//刷新invalidate();}});}private ButtonSildingEvent buttonSildingEvent;/*** 设置完成的监听* @param buttonSilding*/public void setOnListener(ButtonSildingEvent buttonSilding) {this.buttonSildingEvent = buttonSilding;}/*** 按钮滑动到右端的接口*/public interface ButtonSildingEvent {void onOver();}}

简书地址:Android自定义View-滑动解锁按钮

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。