Android自定义View制作动态炫酷按钮实例解析

Android自定义View制作动态炫酷按钮实例解析,第1张

概述普通按钮也就那么几种样式,看着都审美疲劳,先放效果图: 你会不会以为这个按钮是集结了很多动画的产物,我告诉你,并没有。所有的实现都是基于自定义View,采用最底层的onDraw一点一点的画出来的。没有采用

普通按钮也就那么几种样式,看着都审美疲劳,先放效果图:

 

你会不会以为这个按钮是集结了很多动画的产物,我告诉你,并没有。所有的实现都是基于自定义view,采用最底层的onDraw一点一点的画出来的。没有采用一丁点的动画。虽然演示时间很短,但是要完成这么多变化,还是挺吃力。
首先讲解用法: 

public class MainActivity extends Activity { @OverrIDe protected voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); final Animationbutton button = (Animationbutton) findVIEwByID(R.ID.button);// button.setTextSizetouch(25); //设置按下时字体的大小,不设置有默认值// button.setstrokeProgress(10); //设置进度条的厚度,不设置有默认值// button.setcolorBase(color.GREEN); //设置整体基色,不设置有默认值// button.setcolorBack(color.GRAY); //设置进度条的背景色,不设置有默认值// button.setstroke(3); //设置边框的厚度,不设置有默认值// button.setstrokeText(0); //设置文本的厚度,不设置有默认值// button.setTextSize(30); //设置文本的字体大小,不设置有默认值// button.setRound(30); //设置圆角,不设置有默认值 button.setText("登录"); //设置文本,不设置有默认值 button.setMode(Animationbutton.Mode.Hand_Finish); //设置进度条模式,不设置有默认值Mode.auto_Finish button.setonAnimationbuttonClickListener(new Animationbutton.OnAnimationbuttonClickListener() {  @OverrIDe  public voID onClick() {  //stopProgress方法 仅仅在button.setMode(Animationbutton.Mode.Hand_Finish);之后才有效。  button.stopProgress();  } }); }} 

其实如果只需要最普通的功能,根本什么都不用做。因为几乎所有的参数都已经设置了固定内设置。在上面注释掉的函数用法也是用户唯一能用的几个函数,其他函数虽然标示为public,但是却是因为组件之内的方法传递,而不是给外界用户调用的。因此大家如果想自定义样式,可以调用注释里的方法。  

下面开始源码讲解,首先分解功能,所有的变化可以分为三个状态: 
1、默认状态,也就是最初的状态。主要完成的事情为:接收用户的点击,改变背景的样式从空心变为实心,动态改变文本的大小,然后就是逐渐得缩小成一个圆。 
2、进度条状态。主要完成进度条的递进,演示图上只转了一圈。其实可以通过设置一个参数,转动多圈直到用户手动停止,甚至无限转动 
3、结束状态。主要完成由圆的状态变回圆角矩形的状态,并呈现中间的logo  

既然分割出了状态,那么就采用状态机+代理模式来实现这个功能吧。首先是状态的枚举。 

/** * Created by ccwxf on 2016/2/29. * 用于区别状态,有:默认状态、进度条状态、结束状态 */public enum Status { Default,Progress,Finish}

 然后是状态机的接口,也就是所有的状态需要完成的共同的事情:

/** * Created by ccwxf on 2016/2/29. */public interface buttonStatus { /** * @return 对应的Status值 */ Status getStatus(); /** * 这个状态的事件处理代理 * @param mEvent * @return */ boolean ontouchEvent(MotionEvent mEvent); /** * 这个状态的绘制代理 * @param mCanvas * @param mPaint */ voID onDraw(Canvas mCanvas,Paint mPaint);}

 然后我们实现按钮的代码,也就是自定义view: 

/** * Created by ccwxf on 2016/2/29. */public class Animationbutton extends VIEw { private static int color_Base = color.rgb(24,204,149); private static int color_Back = color.rgb(153,153,153); private static int stroke = 3; private static int stroke_Text = 0; private static int stroke_Progress = 10; private static int Text_Size = 30; private static int Text_Size_touch = 25; private static int Round = 30; private static String Text = "提交"; private Mode mode = Mode.auto_Finish; private int maxWIDth; private int maxHeight; private int colorBase = color_Base; private int colorBack = color_Back; private int stroke = stroke; private int strokeText = stroke_Text; private int strokeProgress = stroke_Progress; private int textSize = Text_Size; private int textSizetouch = Text_Size_touch; private int round = Round; private String text = Text; //是否停止进度条,由外界设置 private boolean isProgressstop = false; private Paint mPaint = new Paint(Paint.ANTI_AliAS_FLAG); private buttonStatus status; private OnAnimationbuttonClickListener Listener; public Mode getMode() { return mode; } public voID setMode(Mode mode) { this.mode = mode; } public int getMaxWIDth() { return maxWIDth; } public int getMaxHeight() { return maxHeight; } public int getTextSizetouch() { return textSizetouch; } public voID setTextSizetouch(int textSizetouch) { this.textSizetouch = textSizetouch; } public int getstrokeProgress() { return strokeProgress; } public voID setstrokeProgress(int strokeProgress) { this.strokeProgress = strokeProgress; } public int getcolorBase() { return colorBase; } public voID setcolorBase(int colorBase) { this.colorBase = colorBase; } public int getcolorBack() { return colorBack; } public voID setcolorBack(int colorBack) { this.colorBack = colorBack; } public int getstroke() { return stroke; } public voID setstroke(int stroke) { this.stroke = stroke; } public int getstrokeText() { return strokeText; } public voID setstrokeText(int strokeText) { this.strokeText = strokeText; } public int getTextSize() { return textSize; } public voID setTextSize(int textSize) { this.textSize = textSize; } public int getRound() { return round; } public voID setRound(int round) { this.round = round; } public String getText() { return text; } public voID setText(String text) { this.text = text; } public Animationbutton(Context context) { super(context); } public Animationbutton(Context context,AttributeSet attrs) { super(context,attrs); } public Animationbutton(Context context,AttributeSet attrs,int defStyleAttr) { super(context,attrs,defStyleAttr); } @OverrIDe public boolean ontouchEvent(MotionEvent event) { if (status != null) {  return status.ontouchEvent(event); } return super.ontouchEvent(event); } @OverrIDe protected voID onDraw(Canvas canvas) { if (status != null) {  status.onDraw(canvas,mPaint); } } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) { maxWIDth = MeasureSpec.getSize(wIDthMeasureSpec); maxHeight = MeasureSpec.getSize(heightmeasureSpec); if (maxWIDth != 0 && maxHeight != 0) {  status = new DefaultStatus(this,maxWIDth,maxHeight); } super.onMeasure(wIDthMeasureSpec,heightmeasureSpec); } /** * 改变整体状态 * * @param s 改变的状态 * @param wIDth 目前的宽度 * @param height 目前的高度 */ public voID changeStatus(Status s,int wIDth,int height,int centerX,int centerY) { switch (s) {  case Default:  break;  case Progress:  //改变状态,进入进度条状态  status = new Progressstatus(this,wIDth,height,centerX,centerY);  invalIDate();  break;  case Finish:  //进入结束状态  status = new FinishStatus(this,centerY);  invalIDate();  break; } } /** * 外界设置停止进度条 */ public voID stopProgress(){ this.isProgressstop = true; } /** * 检查是否进度条结束 * @return */ public boolean isProgressstop(){ return isProgressstop; } public enum Mode{ auto_Finish,Hand_Finish } public interface OnAnimationbuttonClickListener{ voID onClick(); } public voID setonAnimationbuttonClickListener(OnAnimationbuttonClickListener Listener){ this.Listener = Listener; } public OnAnimationbuttonClickListener getonAnimationbuttonClickListener(){ return Listener; }}
 

上面实现了一堆的变量参数供用户自定义。然后在ontouchEvent和onDraw方法中,将所有 *** 作都代理出去。 
然后我们来实现第一个状态,也就是默认状态: 

/** * Created by ccwxf on 2016/2/29. */public class DefaultStatus implements buttonStatus { //分别表示处于默认状态内部的四个子状态 private static final int Status_Default = 0; private static final int Status_touch = 1; private static final int Status_Up = 2; private static final int Status_Next = 3; //刷新wIDth时的渐变量以及时间间距 private static final int Delay_Next = 500; private static final int Delay_Frush = 10; private static final int Pixel_Frush = 8; //按钮对象 private Animationbutton button; //按钮对象的长宽与中点坐标(长宽为绘制的长宽,而不是控件的长宽) private int wIDth; private int height; private int centerX; private int centerY; //子状态变量 private int status = Status_Default; private Handler handler = new Handler(); public DefaultStatus(Animationbutton button,int height) { this.button = button; this.wIDth = wIDth; this.height = height; this.centerX = wIDth / 2; this.centerY = height / 2; } @OverrIDe public Status getStatus() { return Status.Default; } @OverrIDe public boolean ontouchEvent(MotionEvent mEvent) { switch (mEvent.getAction()) {  case MotionEvent.ACTION_DOWN:  //按下时,切换到按下子状态  if(status == Status_Default){   status = Status_touch;   button.invalIDate();  }  return true;  case MotionEvent.ACTION_UP:  case MotionEvent.ACTION_CANCEL:  //抬起时,或者移除控件时,切换到抬起子状态  if(status == Status_touch){   status = Status_Up;   button.invalIDate();   //过500ms延迟后开始进行伸缩变化   handler.postDelayed(new Runnable() {   @OverrIDe   public voID run() {    //切换到next子状态    if(status == Status_Up){    status = Status_Next;    }    if(status == Status_Next){    //若长宽不一致,则继续渐变,否则改变状态    if (wIDth >= height) {     wIDth -= Pixel_Frush;     button.invalIDate();     handler.postDelayed(this,Delay_Frush);    }else{     button.changeStatus(Status.Progress,centerY);    }    }   }   },Delay_Next);   //响应监听器   Animationbutton.OnAnimationbuttonClickListener Listener = button.getonAnimationbuttonClickListener();   if(Listener != null){   Listener.onClick();   }  }  break; } return false; } @OverrIDe public voID onDraw(Canvas mCanvas,Paint mPaint) { switch (status) {  case Status_Default:  onDrawDefault(mCanvas,mPaint);  break;  case Status_touch:  onDrawtouch(mCanvas,mPaint);  break;  case Status_Up:  onDrawUp(mCanvas,mPaint);  break;  case Status_Next:  onDrawNext(mCanvas,mPaint);  break; } } /** * 绘制边框,分为空心和实心两种 * * @param mCanvas 画布 * @param mPaint 画笔 * @param style 空心或者实心 * @param padding 边框补白 */ private voID drawRound(Canvas mCanvas,Paint mPaint,Paint.Style style,int padding) { mPaint.setcolor(button.getcolorBase()); int stroke = padding; if (style == Paint.Style.stroke) {  mPaint.setStyle(Paint.Style.stroke);  mPaint.setstrokeWIDth(button.getstroke());  stroke += button.getstroke() / 2; } else {  mPaint.setStyle(Paint.Style.FILL); } //绘制边框 mCanvas.drawRoundRect(new RectF(stroke,stroke,wIDth - stroke,height - stroke),button.getRound(),mPaint); } /** * 画文字,有字体大小和颜色的区别 * * @param mCanvas 画布 * @param mPaint 画笔 * @param textSize 字体大小 * @param textcolor 字体颜色 */ private voID drawText(Canvas mCanvas,int textSize,int textcolor) { mPaint.setcolor(textcolor); mPaint.setstrokeWIDth(button.getstrokeText()); mPaint.setTextSize(textSize); Paint.FontMetrics metrics = mPaint.getFontMetrics(); int textWIDth = (int) mPaint.measureText(button.getText()); int baseline = (int) (height / 2 + (metrics.bottom - metrics.top) / 2 - metrics.bottom); mCanvas.drawText(button.getText(),(wIDth - textWIDth) / 2,baseline,mPaint); } /** * 绘制默认状态的按钮 * * @param mCanvas * @param mPaint */ private voID onDrawDefault(Canvas mCanvas,Paint mPaint) { drawRound(mCanvas,mPaint,Paint.Style.stroke,0); //绘制居中文字 drawText(mCanvas,button.getTextSize(),button.getcolorBase()); } /** * 绘制按下状态的按钮 * * @param mCanvas * @param mPaint */ private voID onDrawtouch(Canvas mCanvas,Paint.Style.FILL,button.getstroke()); //绘制文字,字体要变化 drawText(mCanvas,button.getTextSizetouch(),color.WHITE); } /** * 绘制抬起状态的按钮 * * @param mCanvas * @param mPaint */ private voID onDrawUp(Canvas mCanvas,0); drawText(mCanvas,color.WHITE); } /** * 绘制进入下一状态的按钮 * * @param mCanvas * @param mPaint */ private voID onDrawNext(Canvas mCanvas,Paint mPaint) { mPaint.setcolor(button.getcolorBase()); mPaint.setStyle(Paint.Style.FILL); //绘制边框 if (wIDth >= height) {  mCanvas.drawRoundRect(new RectF(centerX - wIDth / 2,centerY - height / 2,centerX + wIDth / 2,centerY + height / 2),mPaint);  //绘制文字  mPaint.setcolor(color.WHITE);  mPaint.setstrokeWIDth(button.getstrokeText());  mPaint.setTextSize(button.getTextSize());  Paint.FontMetrics metrics = mPaint.getFontMetrics();  int textWIDth = (int) mPaint.measureText(button.getText());  int baseline = (int) (centerY + (metrics.bottom - metrics.top) / 2 - metrics.bottom);  mCanvas.drawText(button.getText(),centerX - textWIDth / 2,mPaint); } else {  mCanvas.drawoval(new RectF(centerX - wIDth / 2,mPaint); } }}

然后是第二个状态,进度条状态: 

/** * Created by ccwxf on 2016/2/29. */public class Progressstatus implements buttonStatus { //转圈的子状态 private static final int Status_Once = 0; private static final int Status_Twice = 1; //转圈的渐变量 private static final int Delay_Progress = 10; private static final int Angle_Progress = 5; private static final int Angle_Default = -90; private static final int Andle_Full = 270; private Animationbutton button; private int wIDth; private int height; private int centerX; private int centerY; private int radius; private int status = Status_Once; //当前的进度 private float progress = Angle_Default; private Handler handler = new Handler(); public Progressstatus(Animationbutton button,int centerY) { this.button = button; this.wIDth = wIDth; this.height = height; this.centerX = centerX; this.centerY = centerY; //绘制起点是stroke的中点,若不减去这个值,则onDraw时,会不完整。 this.radius = (wIDth - button.getstrokeProgress()) / 2; startProgress(); } /** * 开始递归转动进度条 */ private voID startProgress() { handler.postDelayed(new Runnable() {  @OverrIDe  public voID run() {  if(progress >= Andle_Full){   //如果是手动结束模式   if(button.getMode() == Animationbutton.Mode.Hand_Finish && button.isProgressstop()){   //改变状态   button.changeStatus(Status.Finish,centerY);   return;   }else{   if(status == Status_Once){    status = Status_Twice;   }else if(status == Status_Twice){    //如果是自动结束模式,则在第二次进度结束时改变状态    if(button.getMode() == Animationbutton.Mode.auto_Finish){    //改变状态    button.changeStatus(Status.Finish,centerY);    return;    }else{    status = Status_Once;    }   }   //重置进度   progress = Angle_Default;   }  }  progress += Angle_Progress;  button.invalIDate();  handler.postDelayed(this,Delay_Progress);  } },Delay_Progress); } @OverrIDe public Status getStatus() { return Status.Progress; } @OverrIDe public boolean ontouchEvent(MotionEvent mEvent) { return false; } @OverrIDe public voID onDraw(Canvas mCanvas,Paint mPaint) { if(status == Status_Once){  //绘制灰色背景  onDrawCircle(mCanvas,button.getcolorBack());  //绘制绿色进度  onDrawArc(mCanvas,button.getcolorBase(),Angle_Default,progress); }else if(status == Status_Twice){  //绘制绿色背景  onDrawCircle(mCanvas,button.getcolorBase());  //绘制灰色进度  onDrawArc(mCanvas,button.getcolorBack(),progress); } } /** * 画一整个圆作为背景 * @param mCanvas 画布 * @param mPaint 画笔 * @param color 颜色 */ private voID onDrawCircle(Canvas mCanvas,int color){ mPaint.setcolor(color); mPaint.setstrokeWIDth(button.getstrokeProgress()); mPaint.setStyle(Paint.Style.stroke); mCanvas.drawCircle(centerX,centerY,radius,mPaint); } /** * 画一端圆弧 * @param mCanvas 画布 * @param mPaint 画笔 * @param color 颜色 * @param start 开始角度 * @param stop 结束角度 */ private voID onDrawArc(Canvas mCanvas,int color,float start,float stop){ mPaint.setcolor(color); mPaint.setstrokeWIDth(button.getstrokeProgress()); mPaint.setStyle(Paint.Style.stroke); //第三个参数是扫过的角度,起点0默认为右边 mCanvas.drawArc(new RectF(centerX - radius,centerY - radius,centerX + radius,centerY + radius),start,stop - start,false,mPaint); }} 

最后一个状态:

/** * Created by ccwxf on 2016/2/29. */public class FinishStatus implements buttonStatus { private static final int Status_Stretch = 0; private static final int Status_Finish = 1; private static final int stroke_Over = 10; private static final String Text_Over = "√"; private static final int Text_Over_Size = 40; private static final int Delay_Stretch = 10; private static final int Pixel_Stretch = 8; private Animationbutton button; private int wIDth; private int height; private int centerX; private int centerY; private int status = Status_Stretch; private Handler handler = new Handler(); public FinishStatus(Animationbutton button,int centerY) { this.button = button; this.wIDth = wIDth; this.height = height; this.centerX = centerX; this.centerY = centerY; startStretch(); } /** * 开始伸展背景 */ private voID startStretch() { handler.postDelayed(new Runnable() {  @OverrIDe  public voID run() {  if(wIDth < button.getMaxWIDth()){   wIDth += Pixel_Stretch;   button.invalIDate();   handler.postDelayed(this,Delay_Stretch);  }else{   wIDth = button.getMaxWIDth();   if(status == Status_Stretch){   status = Status_Finish;   }   button.invalIDate();  }  } },Delay_Stretch); } @OverrIDe public Status getStatus() { return Status.Finish; } @OverrIDe public boolean ontouchEvent(MotionEvent mEvent) { return false; } @OverrIDe public voID onDraw(Canvas mCanvas,Paint mPaint) { //绘制背景 mPaint.setcolor(button.getcolorBase()); mPaint.setStyle(Paint.Style.FILL); mCanvas.drawRoundRect(new RectF(centerX - wIDth / 2,centerY + height / 2 ),mPaint); //绘制图片 if(status == Status_Finish){  mPaint.setcolor(color.WHITE);  mPaint.setstrokeWIDth(stroke_Over);  mPaint.setTextSize(Text_Over_Size);  Paint.FontMetrics metrics = mPaint.getFontMetrics();  int textWIDth = (int) mPaint.measureText(Text_Over);  int baseline = (int) (height / 2 + (metrics.bottom - metrics.top) / 2 - metrics.bottom);  mCanvas.drawText(Text_Over,mPaint); } }}

好了上面就是所有的源码了。虽然被我概括成三个大状态,但是如果分细一点的话,大概需要9个状态。在各个大状态代码里面的子状态就是这个了。
 怎么使用呢,也非常简单,因为大部分的参数都有内设值了。 

/** * Created by ccwxf on 2016/2/29. */public class MainActivity extends Activity { @OverrIDe protected voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); final Animationbutton button = (Animationbutton) findVIEwByID(R.ID.button);// button.setTextSizetouch(25); //设置按下时字体的大小,不设置有默认值// button.setstrokeProgress(10); //设置进度条的厚度,不设置有默认值// button.setcolorBase(color.GREEN); //设置整体基色,不设置有默认值// button.setcolorBack(color.GRAY); //设置进度条的背景色,不设置有默认值// button.setstroke(3); //设置边框的厚度,不设置有默认值// button.setstrokeText(0); //设置文本的厚度,不设置有默认值// button.setTextSize(30); //设置文本的字体大小,不设置有默认值// button.setRound(30); //设置圆角,不设置有默认值 button.setText("登录"); //设置文本,不设置有默认值 button.setMode(Animationbutton.Mode.Hand_Finish); //设置进度条模式,不设置有默认值Mode.auto_Finish button.setonAnimationbuttonClickListener(new Animationbutton.OnAnimationbuttonClickListener() {  @OverrIDe  public voID onClick() {  //stopProgress方法 仅仅在button.setMode(Animationbutton.Mode.Hand_Finish);之后才有效。  button.stopProgress();  } }); }}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android自定义View制作动态炫酷按钮实例解析全部内容,希望文章能够帮你解决Android自定义View制作动态炫酷按钮实例解析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1148916.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存