1. 程式人生 > >自定義開關View的酷炫效果(ButtonView)

自定義開關View的酷炫效果(ButtonView)

不多說先看圖

這裡寫圖片描述

寫在前頭

最近在看到的一個按鈕動畫,覺得以後在專案中遇到的可能性挺大的,閒的無聊實現了下,程式碼貼在下面,還請各位大神多多指正,互相學習!

程式碼實現

做了比較多的註釋,是自己的學習,也是提供給看的人更清楚明瞭。

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>

寫在後面

先寫到這裡了,上面的程式碼如果您有更好的建議或者思路,請評論告知,希望和大家共同進步,多多交流!如果您有比較好的學習資料,也請多多分享!