Android自定義控件——時鐘、進度條

由於Android提供的空間有限,不能滿足程序的需求,所以纔有了自定義控件

時鐘

首先要寫一個類繼承自View

package com.example.administrator.myselfview.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;

import java.util.Calendar;

/**
 * Created by Administrator on 2015/9/16.
 */
public class MyAlarmview extends View {
    private int width;
    private int height;
    private Paint mPaintLine;
    private Paint mPaintSecondLine;
    private Paint mPaintCricle;
    private Paint mPaintText;
    private Calendar mCalendar;
    public static final int UPDATE_TIME=0X22;
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case UPDATE_TIME:
                    mCalendar=Calendar.getInstance();
                    invalidate();
                    handler.sendEmptyMessageDelayed(UPDATE_TIME,1000);
                    break;
            }
        }
    };
    public MyAlarmview(Context context) {
        super(context);
    }

    public MyAlarmview(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaintLine=new Paint();
        mPaintLine.setColor(Color.BLACK);//設置顏色
        mPaintLine.setStrokeWidth(10);//畫筆寬度

        mPaintSecondLine=new Paint();
        mPaintSecondLine.setColor(Color.GRAY);
        mPaintSecondLine.setStrokeWidth(5);

        mPaintCricle=new Paint();
        mPaintCricle.setColor(Color.BLACK);
        mPaintCricle.setStrokeWidth(10);
        mPaintCricle.setStyle(Paint.Style.STROKE);//圓形畫筆空心

        mPaintText=new Paint();
        mPaintText.setColor(Color.BLACK);
        mPaintText.setTextSize(30);//字體畫筆設置字體大小
        mPaintText.setTextAlign(Paint.Align.CENTER);//讓字體居中顯示

        mCalendar=Calendar.getInstance();

        handler.sendEmptyMessage(UPDATE_TIME);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width=getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        height=getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //先畫一個圓,調用canvas的drawCircle方法,第一個參數爲圓心的橫座標,第二個參數爲圓心縱座標,第三個參數爲半徑,第四個參數爲畫筆
        canvas.drawCircle(width/2,height/2,300,mPaintCricle);
        //劃出12個表示小時的線
        for (int i=1;i<=12;i++){
            canvas.rotate(30,width/2,height/2);//畫布旋轉30度
            canvas.drawLine(width/2,height/2-300,width/2,height/2-280,mPaintLine);
            canvas.drawText(""+i,width/2,height/2-250,mPaintText);
        }
        //劃出表示分鐘的60個點
        for (int i=0;i<60;i++){
            canvas.rotate(6,width/2,height/2);
            canvas.drawLine(width/2,height/2-300,width/2,height/2-290,mPaintLine);
        }
        //用Calendar類得到當前的小時分鐘秒
        int minute=mCalendar.get(Calendar.MINUTE);
        int hour=mCalendar.get(Calendar.HOUR);
        int second=mCalendar.get(Calendar.SECOND);
        //然後得到當前的時間時針分針秒針需要旋轉的角度
        float minDegree=minute/60f*360;
        float hourDegree=(hour*60+minute)/12f/60*360;
        float secondDegree=second/60f*360;

        canvas.save();//保存當前狀態
        canvas.rotate(hourDegree,width/2,height/2);
        canvas.drawLine(width/2,height/2-150,width/2,height/2+10,mPaintLine);
        canvas.restore();//返回之前保存的狀態

        canvas.save();
        canvas.rotate(minDegree,width/2,height/2);
        canvas.drawLine(width/2,height/2-200,width/2,height/2+15,mPaintLine);
        canvas.restore();

        canvas.save();
        canvas.rotate(secondDegree,width/2,height/2);
        canvas.drawLine(width/2,height/2-230,width/2,height/2+20,mPaintSecondLine);
        canvas.restore();
    }
}

在XML文件中定義一下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.administrator.myselfview.view.MyAlarmview
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

由於是自定義控件,所以要寫全名
然後MainActivity中不需要多寫什麼,只需加入這個界面就行。
繼承自View之後需要重寫其構造器,View有四個構造器,這裏重寫其前兩個構造器,並在第二個構造器中定義自定義的畫筆。然後重寫onMeasure()和onDraw()方法,在onMeasure()方法中定義畫布的寬和高,這裏使用的是系統定義的畫布的大小;然後在onDraw()方法中進行對畫布的操作,即作圖。最後利用Handler類來對信息進行處理,使用 invalidate()對畫布進行重畫刷新操作。

進度條

這裏做了三個簡單的進度條,方法都一樣,爲圓形擴散型進度條,矩形填充進度條,弧形旋轉進度條

圓形進度條

同樣首先需要新建一個自定義控件的類並繼承自View,並重寫其兩個構造器和兩個方法

package com.example.administrator.myselfview.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * Created by Administrator on 2015/9/16.
 */
public class MyProgressBallView extends View{
    private int width;
    private int height;
    private Paint mPaintBack;
    private Paint mPaintCurrent;
    private Paint mPaintText;
    private int maxProgress=100;
    private int currentProgress;


    public void setCurrentProgress(int currentProgress) {
        this.currentProgress = currentProgress;

    }

    public MyProgressBallView(Context context) {
        super(context);
    }

    public MyProgressBallView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaintBack=new Paint();
        mPaintBack.setColor(Color.GRAY);
        mPaintBack.setAntiAlias(true);

        mPaintCurrent=new Paint();
        mPaintCurrent.setColor(Color.GREEN);
        mPaintCurrent.setAntiAlias(true);

        mPaintText=new Paint();
        mPaintText.setColor(Color.BLUE);
        mPaintText.setTextSize(80);
        mPaintText.setTextAlign(Paint.Align.CENTER);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width=getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        height=getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        //setMeasuredDimension(width,height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        invalidate();//重新繪製
        canvas.drawCircle(width/2,height/2,300,mPaintBack);//最底下作爲背景的圓
        canvas.drawCircle(width/2,height/2,currentProgress*300f/maxProgress,mPaintCurrent);
        //根據進度實時更新畫出的表示進度的圓
        canvas.drawText(currentProgress*100f/maxProgress+"%",width/2,height/2,mPaintText);
    }//文本畫筆實時更新表示下載進度
}

在自定義View中千萬不要忘記每次都要重新繪製,即invalidate();要不然界面是不會動的。
然後在Activity中簡單的模仿一個下載進度,並把當前進度傳遞到自定義View類中來,好實時地重繪到屏幕上。

package com.example.administrator.myselfview.subactivity;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.example.administrator.myselfview.R;
import com.example.administrator.myselfview.view.MyProgressBallView;

/**
 * Created by Administrator on 2015/9/16.
 */
public class ProgressBallActivity extends Activity {
    private MyProgressBallView myProgressBallView;
    private Button mButton_start;
    private int count=0;
    private static final int PROGRESSBALL=121;
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case PROGRESSBALL:
                    count++;
                    if (count<=100){
                        myProgressBallView.setCurrentProgress(count);
                        handler.sendEmptyMessageDelayed(PROGRESSBALL, 150);

                    }
                    break;
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_progressball);
        mButton_start= (Button) findViewById(R.id.button_progress_ball_start);
        myProgressBallView= (MyProgressBallView) findViewById(R.id.progress_ball);
        mButton_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.sendEmptyMessage(PROGRESSBALL);
            }
        });
    }
}

利用Handler類通過子線程控制UI,設置當前進度。
然後在XML文件中聲明

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/button_progress_ball_start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="開始下載"/>
    <com.example.administrator.myselfview.view.MyProgressBallView
        android:id="@+id/progress_ball"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

這裏定義自定義控件的時候,切記一定要寫全名

弧形進度條

弧形進度條跟圓形是一樣,只不過是繪製圖形的時候用到的方法不一樣而已,其他完全相同,這裏只寫繪製時候的代碼

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        invalidate();
        canvas.drawArc(new RectF(width/2-300,height/2-300,width/2+300,height/2+300),90f,360f,false,mPaintBack);
        canvas.drawArc(new RectF(width/2-300,height/2-300,width/2+300,height/2+300),-90f,currentProgress*360f/maxProgress,false,mPaintCurrent);
        canvas.drawText(currentProgress*100f/maxProgress+"%",width/2,height/2,mPaintText);
    }

矩形進度條

同樣,這裏只是舉出矩形進度條繪製時候的方法

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        invalidate();
        canvas.drawRect(width/2-120,height/2-300,width/2+120,height/2+300,mPaintBack);
        canvas.drawRect(width/2-120,height/2+300-currentProgress*600f/maxProgress,width/2+120,height/2+300,mPaintCurrent);
        canvas.drawText(currentProgress*100f/maxProgress+"%",width/2,height/2,mPaintText);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章