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