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

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

你会不会以为这个按钮是集结了很多动画的产物,我告诉你,并没有。所有的实现都是基于自定义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, width, height, centerX, 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 width, 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, width, height, centerX, 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(), button.getRound(), mPaint);
 }

 /**
 * 画文字,有字体大小和颜色的区别
 *
 * @param mCanvas 画布
 * @param mPaint 画笔
 * @param textSize 字体大小
 * @param textColor 字体颜色
 */
 private void drawText(Canvas mCanvas, Paint mPaint, 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, mPaint, button.getTextSize(), button.getColorBase());
 }

 /**
 * 绘制按下状态的按钮
 *
 * @param mCanvas
 * @param mPaint
 */
 private void onDrawTouch(Canvas mCanvas, Paint mPaint) {
 drawRound(mCanvas, mPaint, Paint.Style.FILL, button.getStroke());
 //绘制文字,字体要变化
 drawText(mCanvas, mPaint, button.getTextSizeTouch(), Color.WHITE);
 }

 /**
 * 绘制抬起状态的按钮
 *
 * @param mCanvas
 * @param mPaint
 */
 private void onDrawUp(Canvas mCanvas, Paint mPaint) {
 drawRound(mCanvas, mPaint, Paint.Style.FILL, 0);
 drawText(mCanvas, mPaint, button.getTextSize(), 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),
   button.getRound(), button.getRound(), 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, baseLine, mPaint);
 } else {
  mCanvas.drawOval(new RectF(centerX - width / 2, centerY - height / 2, centerX + width / 2, centerY + height / 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 width, int height, int centerX, 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, width, height, centerX, 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, width, height, centerX, 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, mPaint, button.getColorBack());
  //绘制绿色进度
  onDrawArc(mCanvas, mPaint, button.getColorBase(), Angle_Default, progress);
 }else if(status == Status_Twice){
  //绘制绿色背景
  onDrawCircle(mCanvas, mPaint, button.getColorBase());
  //绘制灰色进度
  onDrawArc(mCanvas, mPaint, button.getColorBack(), Angle_Default, progress);
 }
 }

 /**
 * 画一整个圆作为背景
 * @param mCanvas 画布
 * @param mPaint 画笔
 * @param color 颜色
 */
 private void onDrawCircle(Canvas mCanvas, Paint mPaint, 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, Paint mPaint, 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 width, int height, int centerX, 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, centerX + width / 2, centerY + height / 2 ),
  button.getRound(), button.getRound(), 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, (width - textWidth) / 2, baseLine, 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();
  }
 });
 }
}

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

(0)

相关推荐

  • Android自定义View实现拖动选择按钮

    本文为大家分享了Android实现拖动选择按钮的具体代码,供大家参考,具体内容如下 效果图 View代码 第一步:自定义属性 <declare-styleable name="DragView"> <attr name="icon_drag" format="reference"/> <attr name="color_circle" format="color"/> &

  • Android自定义控件之开关按钮学习笔记分享

    今天来讲讲自定义单个控件,就拿开关按钮来讲讲,相信大家见了非常多这样的了,先看看效果: 我们可以看到一个很常见的开关按钮,那就来分析分析. 首先: 这是由两张图片构成: ①一张为有开和关的背景图片 ②一张为控制开和关的滑动按钮 第一步: 写个类继承View,并重写几个方法: 第一个为构造函数,重写一个参数的函数和两个参数的函数就够了,因为两个参数的函数能够使用自定义属性 第二个为控制控件的大小–>protected void onMeasure(int widthMeasureSpec, int

  • Android如何自定义按钮效果

    安卓原生的按钮是多么丑,效果是多么单调,大家也是有目共睹的. 要做一个APP少不了使用按钮,一个好看的按钮少不了好看的效果和外表,这次主要跟大家讲讲如何用drawable的xml文件弄一些好看的自定义样式. 首先是外表 在APP中四四方方,灰色底黑色字的按钮是很难看的,我们希望看到的是圆角,彩色,白字(根据你的个人审美也可以是其他样式). 首先是在layout里新建一个按钮 ,然后在drawable文件夹里新建一个drawable resource file ,不妨起名为shape ,加一个se

  • Android 自定义按钮点击事件和长按事件对比

     Android 自定义按钮点击事件和长按事件对比 一个按钮同时实现点击和长按事件,有时候会有冲突,我们针对这一现象来自定义按钮来区分点击和长按事件 1.xml中 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="mat

  • Android自定义控件实现温度旋转按钮效果

    首先看下效果图 温度旋转按钮 实现思路 初始化一些参数 绘制刻度盘 绘制刻度盘下的圆弧 绘制标题与温度标识 绘制旋转按钮 绘制温度 处理滑动事件 提供一些接口方法 实现方法 初始化一些参数 public class TempControlView extends View { // 控件宽 private int width; // 控件高 private int height; // 刻度盘半径 private int dialRadius; // 圆弧半径 private int arcRa

  • Android自定义实现开关按钮代码

    我们在应用中经常看到一些选择开关状态的配置文件,做项目的时候用的是android的Switch控件,但是感觉好丑的样子子 个人认为还是自定义的比较好,先上个效果图: 实现过程: 1.准备开关不同状态的两张图片放入drawable中. 2.xml文件中添加代码: <ToggleButton android:id="@+id/switch1" android:layout_width="wrap_content" android:layout_height=&qu

  • 自定义滑动按钮为例图文剖析Android自定义View绘制

    自定义View一直是横在Android开发者面前的一道坎. 一.View和ViewGroup的关系 从View和ViewGroup的关系来看,ViewGroup继承View. View的子类,多是功能型的控件,提供绘制的样式,比如imageView,TextView等,而ViewGroup的子类,多用于管理控件的大小,位置,如LinearLayout,RelativeLayout等,从下图可以看出 从实际应用中看,他们又是组合关系,我们在布局中,常常是一个ViewGroup嵌套多个ViewGro

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

    普通按钮也就那么几种样式,看着都审美疲劳,先放效果图: 你会不会以为这个按钮是集结了很多动画的产物,我告诉你,并没有.所有的实现都是基于自定义View,采用最底层的onDraw一点一点的画出来的.没有采用一丁点的动画.虽然演示时间很短,但是要完成这么多变化,还是挺吃力. 首先讲解用法: public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState)

  • Android自定义View实现简单炫酷的球体进度球实例代码

    前言 最近一直在研究自定义view,正好项目中有一个根据下载进度来实现球体进度的需求,所以自己写了个进度球,代码非常简单.先看下效果: 效果还是非常不错的. 准备知识 要实现上面的效果我们只要掌握两个知识点就好了,一个是Handler机制,用于发消息刷新我们的进度球,一个是clipDrawable.网上关于Handler的教程很多,这里重点介绍一下clipDrawable,进度球的实现全靠clipDrawable. clipDrawable 如下图所示:ClipDrawable和InsertDr

  • Android自定义view制作抽奖转盘

    本文实例为大家分享了Android自定义view制作抽奖转盘的具体代码,供大家参考,具体内容如下 效果图 TurntableActivity package com.bawei.myapplication.turntable; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; im

  • Android自定义view制作绚丽的验证码

    废话不多说了,先给大家展示下自定义view效果图,如果大家觉得还不错的话,请继续往下阅读. 怎么样,这种验证码是不是很常见呢,下面我们就自己动手实现这种效果,自己动手,丰衣足食,哈哈~ 一. 自定义view的步骤 自定义view一直被认为android进阶通向高手的必经之路,其实自定义view好简单,自定义view真正难的是如何绘制出高难度的图形,这需要有好的数学功底(后悔没有好好学数学了~),因为绘制图形经常要计算坐标点及类似的几何变换等等.自定义view通常只需要以下几个步骤: 写一个类继承

  • Android自定义view仿QQ的Tab按钮动画效果(示例代码)

    话不多说 先上效果图 实现其实很简单,先用两张图 一张是背景的图,一张是笑脸的图片,笑脸的图片是白色,可能看不出来.实现思路:主要是再触摸view的时候同时移动这两个图片,但是移动的距离不一样,造成的错位感,代码很简单: import android.content.Context import android.graphics.* import android.util.AttributeSet import android.view.MotionEvent import android.vi

  • Android自定义View实现等级滑动条的实例

     Android自定义View实现等级滑动条的实例 实现效果图: 思路: 首先绘制直线,然后等分直线绘制点: 绘制点的时候把X值存到集合中. 然后绘制背景图片,以及图片上的数字. 点击事件down的时候,换小图片为大图片.move的时候跟随手指移动. up的时候根据此时的X计算最近的集合中的点,然后自动吸附回去. 1,自定义属性 <?xml version="1.0" encoding="utf-8"?> <resources> <de

  • Android自定义View实现箭头沿圆转动实例代码

    具体代码如下所示: //MyCircleView类 public class MyCircleView extends View{ //当前画笔画圆的颜色 private int CurrenCircleBoundColor; private Paint paint; ////从xml中获取的颜色 private int circleBundColor; private float circleBoundWidth; private float pivotX; private float piv

  • Android自定义view实现动态柱状图

    先看一下动态柱状图效果. 主要功能是可以自定义指定的字体,柱状图颜色,动态效果. 在自定义view public class Histogram extends View { int MAX = 100;//矩形显示的最大值 int corner = 0; //矩形的角度. 设置为0 则没有角度. double data = 0.0;//显示的数 double tempData = 0; //初始数据 int textPadding = 50; //字体与矩形图的距离 Paint mPaint;

  • android自定义view制作圆形进度条效果

    还是我们自定View的那几个步骤: 1.自定义View的属性 2.在View的构造方法中获得我们自定义的属性 [ 3.重写onMesure ] 4.重写onDraw 1.自定义属性: <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CustomTitleView"> <attr name="m

  • Android自定义View制作仪表盘界面

    前言 最近我跟自定义View杠上了,甚至说有点上瘾到走火入魔了.身为菜鸟的我自然要查阅大量的资料,学习大神们的代码,这不,前两天正好在郭神在微信公众号里推送一片自定义控件的文章--一步步实现精美的钟表界面.正适合我这种菜鸟来学习,闲着没事,我就差不多依葫芦画瓢也写了一个自定义表盘View,现在纯粹最为笔记记录下来.先展示下效果图: 下面进入正题 自定义表盘属性 老规矩,先在attrs文件里添加表盘自定义属性 <declare-styleable name="WatchView"&

随机推荐