#不多说先看图
#写在前头
最近在看到的一个按钮动画,觉得以后在项目中遇到的可能性挺大的,闲的无聊实现了下,代码贴在下面,还请各位大神多多指正,互相学习!
#代码实现
做了比较多的注释,是自己的学习,也是提供给看的人更清楚明了。
public class ButtonView extends View {
// private OnClickListener mListener;
//默认初始高度
private int rect_height = 0;
//灰色
private Paint paint_gray;
//橙色
private Paint paint_yellow;
//圆形的左、上、右、下
private int circle_left, circle_top, circle_right, circle_bottom;
//圆形半径
private int circle_radius;
//默认padding
private int DEFAULT_PADDING = 20;
//上下文
private Context context;
//打开标志
private boolean openFlag = false;
//第一次标志(第一次进入时是灰色的按钮)
private boolean firstFlag = true;
//秒数,默认为5 单位是毫秒哦
private int sleepTime = 5;
//继承的构造函数
public ButtonView(Context context) {
this(context, null);
}
public ButtonView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//保存上下文
this.context = context;
//初始化数据
initData();
}
/**
* 初始化数据
*/
private void initData() {
//初始化灰色画笔
paint_gray = new Paint();
//抗锯齿
paint_gray.setAntiAlias(true);
//设置画笔颜色
paint_gray.setColor(Color.GRAY);
//Paint.Style.FILL:填充内部Paint.Style.FILL_AND_STROKE :填充内部和描边Paint.Style.STROKE :描边
paint_gray.setStyle(Paint.Style.STROKE);
//线条的末端为圆弧
paint_gray.setStrokeCap(Paint.Cap.ROUND);
//画笔的宽度
paint_gray.setStrokeWidth(11f);
//初始化橙色画笔
paint_orange= new Paint();
paint_orange.setAntiAlias(true);
paint_orange.setColor(context.getResources().getColor(R.color.orange));
paint_orange.setStyle(Paint.Style.STROKE);
paint_orange.setStrokeCap(Paint.Cap.ROUND);
paint_orange.setStrokeWidth(12f);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//得到尺寸
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
//得到模式
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
// 一般来说,自定义控件都会去重写View的onMeasure方法,因为该方法指定该控件在屏幕上的大小。
// protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
// onMeasure传入的两个参数是由上一层控件传入的大小,有多种情况,重写该方法时需要对计算控件的实际大小,然后调用setMeasuredDimension(int, int)设置实际大小。
// onMeasure传入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值。我们需要通过int mode = MeasureSpec.getMode(widthMeasureSpec)得到模式,
// 用int size = MeasureSpec.getSize(widthMeasureSpec)得到尺寸。
// mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。
// MeasureSpec.EXACTLY是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
// MeasureSpec.AT_MOST是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
// MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
switch (widthSpecMode) {
case MeasureSpec.EXACTLY:
//按照父类尺寸小的确定宽和高
if (widthSpecSize <= heightSpecSize) {
heightSpecSize = widthSpecSize;
} else {
widthSpecSize = heightSpecSize;
}
circle_radius = (widthSpecSize - 2 * DEFAULT_PADDING) / 2;
circle_left = DEFAULT_PADDING;
circle_top = DEFAULT_PADDING;
circle_right = circle_left + widthSpecSize - 2 * DEFAULT_PADDING;
circle_bottom = circle_top + heightSpecSize - 2 * DEFAULT_PADDING;
setMeasuredDimension(widthSpecSize, heightSpecSize);
break;
case MeasureSpec.AT_MOST:
break;
case MeasureSpec.UNSPECIFIED:
break;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
RectF rectf = new RectF(circle_left, circle_top, circle_right, circle_bottom);
if (firstFlag && openFlag) {
//画圆和线 rectf圆形的外部矩形区域 -60起点 300圆的大小 paint_yellow画笔
canvas.drawArc(rectf, -60, 300, false, paint_orange);
canvas.drawLine(circle_left + circle_radius, circle_top, circle_left + circle_radius, circle_top + circle_radius, paint_orange);
} else {
//第一次进入,画一个灰色的按钮(就是每次进入界面的时候)
if (firstFlag) {
canvas.drawArc(rectf, -60, 300, false, paint_gray);
canvas.drawLine(circle_left + circle_radius, circle_top, circle_left + circle_radius, circle_top + circle_radius, paint_gray);
} else {
//如果打开,画橙色的圆
if (openFlag) {
if (rect_height < circle_radius) {
rect_height += 5;
canvas.drawLine(circle_left + circle_radius, circle_top + circle_radius, circle_left + circle_radius, circle_top + circle_radius - rect_height, paint_orange);
canvas.drawArc(rectf, -60, (float) rect_height * 300 / circle_radius, false, paint_orange);
//每次绘制都间隔的时间
SystemClock.sleep(sleepTime);
//更新界面
invalidate();
}
canvas.drawLine(circle_left + circle_radius, circle_top + circle_radius, circle_left + circle_radius, circle_top + circle_radius - rect_height, paint_orange);
canvas.drawArc(rectf, -60, (float) rect_height * 300 / circle_radius, false, paint_orange);
} else { //如果关闭,画灰色的圆
if (rect_height < circle_radius) {
rect_height += 5;
canvas.drawLine(circle_left + circle_radius, circle_top + circle_radius, circle_left + circle_radius, circle_top + circle_radius - rect_height, paint_gray);
//根据比例绘制圆形
canvas.drawArc(rectf, -60, (float) rect_height * 300 / circle_radius, false, paint_gray);
//每次绘制都间隔的时间
SystemClock.sleep(sleepTime);
//更新界面
invalidate();
}
canvas.drawLine(circle_left + circle_radius, circle_top + circle_radius, circle_left + circle_radius, circle_top + circle_radius - rect_height, paint_gray);
canvas.drawArc(rectf, -60, (float) rect_height * 300 / circle_radius, false, paint_gray);
}
}
}
}
/**
* 开关标志
*/
public void click() {
firstFlag = false;
//高度为0
rect_height = 0;
openFlag = !openFlag;
//绘制成初始状态
invalidate();
}
/**
* 设置秒数
*/
public void setSleepTime(int sleepTime) {
this.sleepTime = sleepTime;
}
/**
* 设置view打开(就是主动设置为橙色)
*/
public void setOpened() {
openFlag = true;
invalidate();
}
}
#使用
public class MainActivity extends AppCompatActivity {
private boolean isFirst = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ButtonView viewById = (ButtonView) findViewById(R.id.ButtonView);
Button button = (Button) findViewById(R.id.button);
final TextView text = (TextView) findViewById(R.id.text);
//毫秒
viewById.setSleepTime(20);
//设置开始颜色为打开状态
// viewById.setOpened();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!isFirst){
viewById.click();
isFirst = true;
text.setText("状态:打开");
}else {
//无动画效果
// viewById.setOpened();
//有动画效果
viewById.click();
isFirst = false;
text.setText("状态:关闭");
}
}
});
}
}
#xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.rmyh.customview.ButtonView
android:id="@+id/ButtonView"
android:layout_centerInParent="true"
android:layout_width="200dp"
android:layout_height="2000dp" />
<TextView
android:id="@+id/text"
android:text="状态:关闭"
android:layout_below="@+id/ButtonView"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/button"
android:text="打开/关闭"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
#写在后面
先写到这里了,上面的代码如果您有更好的建议或者思路,请评论告知,希望和大家共同进步,多多交流!如果您有比较好的学习资料,也请多多分享!