Android自定義view之實現(xiàn)進度球

前言

最近一直在研究自定義view验庙,正好項目中有一個根據下載進度來實現(xiàn)球體進度的需求幌墓,所以自己寫了個進度球容客,代碼非常簡單。先看下效果:


在這里插入圖片描述

效果還是非常不錯的住涉。

準備知識

要實現(xiàn)上面的效果我們只要掌握兩個知識點就好了,一個是Handler機制钠绍,用于發(fā)消息刷新我們的進度球舆声,一個是clipDrawable。網上關于Handler的教程很多柳爽,這里重點介紹一下clipDrawable纳寂,進度球的實現(xiàn)全靠clipDrawable。
clipDrawable
如下圖所示:ClipDrawable和InsertDrawable一樣繼承DrawableWrapper,DrawableWrapper繼承Drawable泻拦。

在這里插入圖片描述

ClipDrawable是可以進行裁剪操作的drawable毙芜,提供了函數(shù)setLevel(@IntRange(from=0,to=10000) int level)來設置裁剪的大小。level越大圖片越大争拐。level=0時圖片完全不顯示腋粥,level=10000時圖片完全顯示。

        ClipDrawable clipDrawable =  (ClipDrawable) getContext().getResources().getDrawable(R.drawable.bottom_top_clip_gradient_color);//獲取圖片
        clipDrawable.setLevel(100);//進行裁剪

一般還要設置裁剪的方向架曹,垂直裁剪還是水平裁剪隘冲,我們這個進度球用的是垂直從下向上裁剪。
思路:知道了ClipDrawable的用法绑雄,進度球就好實現(xiàn)了展辞。只需要一個球形的圖片,從下往上裁剪万牺,通過設置setLevel從0到10000罗珍,就可以實現(xiàn)進度球從0到進度100的效果了洽腺。

實現(xiàn)

1、定義BallProgress覆旱,BallProgress繼承View,重寫onDraw()方法蘸朋,用于實現(xiàn)進度球的view。

/**
 * Created time 15:02.
 *
 * @author huhanjun
 * @since 2018/12/26
 */
public class BallProgress extends View {
    private float mProgress = 0.0f;   //取值位 0 - 1.0

    private boolean selected = true;

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

    public BallProgress(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public BallProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mProgressPaint = new Paint();//初始化扣唱,定義畫筆藕坯。
        mProgressPaint.setAntiAlias(true);//設置抗鋸齒
    }

    public float getProgress() {
        return mProgress;
    }

    public void setProgress(float progress) {//設置進度,通過進度的大小實現(xiàn)裁剪的大小
        mProgress = progress;
        invalidate();
    }

    private Paint mProgressPaint;


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Bitmap dst = getRectangleBitmap();//獲取bitmap
        setLayerType(LAYER_TYPE_HARDWARE, null);  //開啟硬件離屏緩存
        canvas.drawBitmap(dst, 0, 0, mProgressPaint);
    }
    private Bitmap getRectangleBitmap() {
        int width = getWidth();
        int height = getHeight();
        
        Bitmap dstBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        
        ClipDrawable clipDrawable = null;
            clipDrawable = (ClipDrawable) getContext().getResources().getDrawable(R.drawable.bottom_top_clip_single_color);//獲取球形的背景圖片噪沙,用于裁剪炼彪,就是上面看到的進度球中的圖片
            
        clipDrawable.setBounds(new Rect(0, 0, width, height));//設置邊界
        
        clipDrawable.setLevel((int) (10000 * mProgress));//設置進度,
        
        Canvas canvas = new Canvas(dstBitmap);//設置畫布
        
        clipDrawable.draw(canvas);//繪制
        
        return dstBitmap;//將bitmap返回
    }

}

有了自定義的BallProgress正歼,就可以在布局中使用了霹购,定義的xml文件如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.admin.floatprogressbar.BallProgress
        android:id="@+id/progress"
        android:layout_width="@dimen/progress_size"
        android:layout_height="@dimen/progress_size"
        android:layout_centerInParent="true" />
    <ImageView
        android:layout_width="@dimen/progress_size"
        android:layout_height="@dimen/progress_size"
        android:layout_centerInParent="true"
        android:background="@drawable/main_tab_un_select_bg" />

</RelativeLayout>

上面布局中的ImageView是懸浮球的邊界。在MainActivity中來定時的改變進度球的大小朋腋。代碼如下:

public class MainActivity extends AppCompatActivity {
    private final int PROGRESS_MESSAGE = 0;
    private float progress = 0.0f;
    private BallProgress mBallProgress;
    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case PROGRESS_MESSAGE:
                    progress = (progress > 0.9f) ? 0.9f : progress;
                    mBallProgress.setProgress(progress);//接收消息齐疙,改變進度球的進度
                    break;
            }
            return true;
        }
    });
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initAction();
    }

    private void initView() {
        mBallProgress = findViewById(R.id.progress);
    }
    //發(fā)消息
    private void initAction() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    progress += 0.02f;
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mHandler.sendEmptyMessage(PROGRESS_MESSAGE);//每隔100毫秒發(fā)送一次消息,對進度球進度進行更新旭咽。
                }
            }
        }).start();
    }

}

上面代碼在inAction()中開一個線程贞奋,每隔100毫秒發(fā)送消息,在handler中處理更新穷绵。實際應用中轿塔,可以是跟業(yè)務相關的具體進度。

總結

自定義進度球仲墨,用的是繼承view勾缭,并且通過自定義畫筆,重寫onDraw()方法來實現(xiàn)目养,一般自定義view都會重寫onDraw()方法,一般進度條都是ClipDrawable來實現(xiàn)的俩由。
源碼地址:進度球代碼

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市癌蚁,隨后出現(xiàn)的幾起案子幻梯,更是在濱河造成了極大的恐慌,老刑警劉巖努释,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碘梢,死亡現(xiàn)場離奇詭異,居然都是意外死亡伐蒂,警方通過查閱死者的電腦和手機煞躬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恩沛,你說我怎么就攤上這事在扰。” “怎么了复唤?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵健田,是天一觀的道長烛卧。 經常有香客問我佛纫,道長,這世上最難降的妖魔是什么总放? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任呈宇,我火速辦了婚禮,結果婚禮上局雄,老公的妹妹穿的比我還像新娘甥啄。我一直安慰自己,他們只是感情好炬搭,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布蜈漓。 她就那樣靜靜地躺著,像睡著了一般宫盔。 火紅的嫁衣襯著肌膚如雪融虽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天灼芭,我揣著相機與錄音有额,去河邊找鬼。 笑死彼绷,一個胖子當著我的面吹牛巍佑,可吹牛的內容都是我干的。 我是一名探鬼主播寄悯,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼萤衰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了猜旬?” 一聲冷哼從身側響起腻菇,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎昔馋,沒想到半個月后筹吐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡秘遏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年丘薛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邦危。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡洋侨,死狀恐怖舍扰,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情希坚,我是刑警寧澤边苹,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站裁僧,受9級特大地震影響个束,放射性物質發(fā)生泄漏。R本人自食惡果不足惜聊疲,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一茬底、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧获洲,春花似錦阱表、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至门岔,卻和暖如春爱致,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背固歪。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工蒜鸡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人牢裳。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓逢防,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蒲讯。 傳聞我的和親對象是個殘疾皇子忘朝,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內容