不多說先看圖
寫在前頭
最近在看到的一個按鈕動畫,覺得以後在項目中遇到的可能性挺大的,閒的無聊實現了下,代碼貼在下面,還請各位大神多多指正,互相學習!
代碼實現
做了比較多的註釋,是自己的學習,也是提供給看的人更清楚明瞭。
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>
寫在後面
先寫到這裏了,上面的代碼如果您有更好的建議或者思路,請評論告知,希望和大家共同進步,多多交流!如果您有比較好的學習資料,也請多多分享!