最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android使用自定義View實(shí)現(xiàn)橫行時(shí)間軸效果

 更新時(shí)間:2019年12月15日 15:39:53   作者:Android架構(gòu)師丨小熊  
這篇文章主要給大家介紹了關(guān)于Android使用自定義View實(shí)現(xiàn)橫行時(shí)間軸效果的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Android具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

前言

本篇文章會(huì)說下如何使用并且要用麻煩的自定義 view 去實(shí)現(xiàn)時(shí)間軸效果,以及如何分析、實(shí)現(xiàn)自定義 view。 需要具備的知識(shí):Paint、Canvas、自定義 view 的繪制流程。

歡迎留言交流。

一、已經(jīng)有很多 RecycleView 實(shí)現(xiàn)時(shí)間軸的例子,為何還要費(fèi)勁的使用自定義 view 去實(shí)現(xiàn)時(shí)間軸?

首先看下最終想要的效果:


根據(jù)上圖可以總結(jié)出以下幾點(diǎn):

  1. 每個(gè)階段要顯示時(shí)間、階段名、狀態(tài)圖標(biāo)、中間有虛線;
  2. 文字上下交錯(cuò)顯示;
  3. 相鄰階段的文字在垂直方向上是可以相交的;
  4. 時(shí)間軸的個(gè)數(shù)不確定,但是要鋪滿屏幕并且不可滑動(dòng); 如果只實(shí)現(xiàn)上兩點(diǎn)的效果,使用 RecycleView 無疑是最好的選擇,但是要同時(shí)實(shí)現(xiàn)以上整個(gè)效果目前想到的最好的辦法就是使用自定義 view。

二、如何開始?

相信也有人跟我一樣,對自定義的繪制過程 view、canvas、path、paint 的使用有了解,但是真的要去寫自定義 view 確不知道從何開始,不知道第一步如何下手。我個(gè)人的總結(jié)就是:想要的太多,遲遲不動(dòng)手,所以有想法一定要去動(dòng)手試驗(yàn)! 不要想著寫完第一次運(yùn)行就是最終想展示的完美效果,而是要抱著整體拆分成不重復(fù)的小塊,然后去繪制重復(fù)塊,然后去一點(diǎn)點(diǎn)實(shí)現(xiàn)一步步完美的心態(tài)才能做出來。

所以首先要把想實(shí)現(xiàn)的 view 拆分成一個(gè)個(gè)小的可繪制的并且沒有重復(fù)的塊,以目前想實(shí)現(xiàn)的時(shí)間軸效果來說,最小可繪制無重復(fù)塊也就是只包括一個(gè)時(shí)間結(jié)點(diǎn)的塊如圖:


它包括:

  • 垂直居中的一條虛線;
  • 一個(gè)表示狀態(tài)的圖標(biāo);
  • 一個(gè)顯示時(shí)間的文本塊;
  • 一個(gè)顯示階段名的文本塊;

三、開始畫

有了上面的分析,接下來就要開始畫了。

1. 畫中間的線

首先畫虛線,如果虛線不知道怎么畫,可以先畫一條實(shí)線,然后再去找畫虛線的方法。

使用 canvas 中畫線的方法 drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) 根據(jù)參數(shù)得知需知道線的起點(diǎn)與終點(diǎn)坐標(biāo)以及一個(gè) paint 對象,因?yàn)槭谴怪本又星覚M穿整個(gè)控件的直線所以可以確定兩個(gè)點(diǎn)的 y 坐標(biāo)是一樣的,也就是控件高的一半,起點(diǎn)的 x 坐標(biāo)為0,終點(diǎn)的 x 坐標(biāo)為控件的寬。也就是知道控件的寬和高之后就可以繪制出這條線。獲取控件的寬高,可以在 onMeasure 方法中獲?。?/p>

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  mViewWidth = MeasureSpec.getSize(widthMeasureSpec) - dip2px(mContext, mSafeDistance * 2);
  mViewHeight = MeasureSpec.getSize(heightMeasureSpec);
}

畫線的代碼(在 onDraw 方法中添加,下面其它的繪制方法同樣是在 onDraw 方法中添加):

// 定義畫筆,并設(shè)置相關(guān)屬性
Paint mLinePaint = new Paint();
mLinePaint.setColor(Color.parseColor("#999999"));
mLinePaint.setStrokeWidth(1);
mLinePaint.setStyle(Paint.Style.STROKE);
// 畫虛線
canvas.drawLine(0, mViewHeight / 2, mViewWidth, mViewHeight / 2, mLinePaint);

2. 畫圖標(biāo)

canvas 畫圖標(biāo)的方法:drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint),根據(jù)方法的參數(shù)去分析如何準(zhǔn)備值,這里需要一個(gè) bitmap 對象,起點(diǎn)坐標(biāo)以及 paint。bitmap 對象可以將資源文件 drawable 轉(zhuǎn)為 bitmap 格式;坐標(biāo)就是控件的中心點(diǎn)。畫圖標(biāo)的代碼:

// 圖標(biāo) x,y 坐標(biāo)
Bitmap statusBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.ic_no_pass);
float bX = mViewWidth / 2;
// 垂直的中心點(diǎn)在圖標(biāo)的頂部,所以要減去 bitmap 高的一半
float bY = mViewHeight / 2 - statusBitmap.getHeight() / 2f;
Paint mBitmapPaint = new Paint();
mBitmapPaint.setFilterBitmap(true);
canvas.drawBitmap(statusBitmap, bX, bY, mBitmapPaint);

3. 畫文本

canvas 畫文本的方法:drawText(@NonNull String text, float x, float y, @NonNull Paint paint),依然是根據(jù)方法得知需要知道繪制的內(nèi)容,開始的坐標(biāo)點(diǎn)以及 paint。當(dāng)文本在圖標(biāo)上方時(shí),文本的 y 坐標(biāo)需要使用圖標(biāo)的 y 坐標(biāo)減去文本到圖標(biāo)的距離,x 坐標(biāo)同圖片的 x 坐標(biāo)一樣;當(dāng)文本在圖標(biāo)下方時(shí),文本的 y 坐標(biāo)需要使用圖標(biāo)的 y 坐標(biāo)加上文本到圖標(biāo)的距離。畫文本的代碼:

// 定義畫筆
Paint mDatePaint = new Paint();
mDatePaint.setColor(Color.parseColor("#666666"));
mDatePaint.setTextSize(dip2px(mContext, 12));
mDatePaint.setStyle(Paint.Style.FILL);
mDatePaint.setTextAlign(Paint.Align.CENTER);
mDatePaint.setAntiAlias(true);

Paint mNamePain = new Paint();
mNamePain.setColor(Color.parseColor("#666666"));
mNamePain.setTextSize(dip2px(mContext, 13));
mNamePain.setStyle(Paint.Style.FILL);
mNamePain.setTextAlign(Paint.Align.CENTER);
mNamePain.setAntiAlias(true);

// 定義坐標(biāo)變量
float dateX = bX + statusBitmap.getWidth() / 2f;
float dateY;
dateY = mViewHeight / 2 - dip2px(mContext, 19);

// 畫文字,在圖標(biāo)上
canvas.drawText("有效時(shí)間", dateX, dateY, mNamePain);
canvas.drawText("09.27-09.29", dateX, dateY - dateTextHeight mDatePaint);

// 畫文字,在圖標(biāo)下
dateY = mViewHeight / 2 + dip2px(mContext, 19);
canvas.drawText("09.27-09.29", dateX, dateY, mDatePaint);
canvas.drawText("有效時(shí)間", dateX, dateY + dateTextHeigh, mNamePain);

4. 由局部到整體

上面已經(jīng)完成了只有一個(gè)時(shí)間點(diǎn)的繪制,接下來思考如果有多個(gè)時(shí)間點(diǎn)時(shí)如何繪制。只有一個(gè)時(shí)間點(diǎn)時(shí)計(jì)算坐標(biāo)是以控件的寬高進(jìn)行計(jì)算,那么當(dāng)有兩個(gè)時(shí)間點(diǎn)的時(shí)候需要首先把控件均分成兩部分,然后在均分的部分中計(jì)算對應(yīng)的坐標(biāo),完成繪制。當(dāng)有三個(gè)時(shí)間點(diǎn)的時(shí)候需要均分為三部分,然后在各自的部分計(jì)算對應(yīng)的坐標(biāo),完成繪制。所以得到不論時(shí)間點(diǎn)的個(gè)數(shù)有多少繪制的方法不會(huì)改變,需要改變的是繪制時(shí)候用到的點(diǎn)的坐標(biāo)。其實(shí)已經(jīng)可以看出,當(dāng)多個(gè)點(diǎn)的時(shí)候需要循環(huán)一下,代碼如下:

// 得到多個(gè)點(diǎn)時(shí),其中每個(gè)部分的寬,itevW 也就等同與上面只有一個(gè)時(shí)間點(diǎn)時(shí)控件的寬
float itemW = mViewWidth / mDataList.size();
for (int i = 0; i < mDataList.size(); i++) {
  // 完成相關(guān)計(jì)算、繪制
}

5. 完善

到這里,整個(gè)分析及繪制就差不多要結(jié)束了。

繪制虛線的方法:mLinePaint.setPathEffect(new DashPathEffect(new float[]{10, 10}, 0));

繪制虛線時(shí)遇到一個(gè)問題,在手機(jī)上不顯示虛線效果,后來查到需要關(guān)閉 view 層的硬件加速:setLayerType(View.LAYER_TYPE_SOFTWARE, null);

繪制文本時(shí)的中心點(diǎn)計(jì)算需要注意下

paint、bitmap 等變量的初始化建議放到初始化方法中去做,不建議在 onDraw 方法中做。

四、總結(jié)

關(guān)于自定義 view 一定要多看,多嘗試。

好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。

相關(guān)文章

  • Flutter投票組件使用方法詳解

    Flutter投票組件使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了Flutter投票組件的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Flutter?Animation實(shí)現(xiàn)縮放和滑動(dòng)動(dòng)畫效果

    Flutter?Animation實(shí)現(xiàn)縮放和滑動(dòng)動(dòng)畫效果

    這篇文章主要為大家詳細(xì)介紹了Flutter?Animation實(shí)現(xiàn)縮放和滑動(dòng)動(dòng)畫效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Android 藍(lán)牙自動(dòng)匹配PIN碼跳過用戶交互示例

    Android 藍(lán)牙自動(dòng)匹配PIN碼跳過用戶交互示例

    本篇文章主要介紹了Android 藍(lán)牙自動(dòng)匹配PIN碼跳過用戶交互示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • Android自定義LocationMarker的實(shí)現(xiàn)詳解

    Android自定義LocationMarker的實(shí)現(xiàn)詳解

    這篇文章主要為大家詳細(xì)介紹一個(gè)比較簡單的東西:自定義繪制Marker 其實(shí)就是自定義view, 跟軌跡沒太多關(guān)聯(lián),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-02-02
  • Android如何通過命令行操作Sqlite3數(shù)據(jù)庫的方法

    Android如何通過命令行操作Sqlite3數(shù)據(jù)庫的方法

    這篇文章主要介紹了Android如何通過命令行操作Sqlite3數(shù)據(jù)庫的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • 自定義視圖view之環(huán)形進(jìn)度條

    自定義視圖view之環(huán)形進(jìn)度條

    這篇文章主要介紹了自定義視圖view之環(huán)形進(jìn)度條,這次介紹了4種不同的效果,直接上代碼了,需要的朋友可以參考下
    2023-04-04
  • 一個(gè)簡單的toolabar結(jié)合drawlayout使用方法

    一個(gè)簡單的toolabar結(jié)合drawlayout使用方法

    這篇文章主要為大家詳細(xì)介紹了一個(gè)簡單的toolabar結(jié)合drawlayout的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Flutter 實(shí)現(xiàn)進(jìn)度條效果

    Flutter 實(shí)現(xiàn)進(jìn)度條效果

    在一些上傳頁面炫酷的進(jìn)度條效果都是怎么實(shí)現(xiàn)的,今天小編通過本文給大家分享Flutter 一行代碼快速實(shí)現(xiàn)你的進(jìn)度條效果,感興趣的朋友一起看看吧
    2020-05-05
  • Android編程設(shè)計(jì)模式之抽象工廠模式詳解

    Android編程設(shè)計(jì)模式之抽象工廠模式詳解

    這篇文章主要介紹了Android編程設(shè)計(jì)模式之抽象工廠模式,結(jié)合實(shí)例形式詳細(xì)分析了Android抽象工廠模式的概念、原理、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-12-12
  • Android編程中Handler原理及用法實(shí)例分析

    Android編程中Handler原理及用法實(shí)例分析

    這篇文章主要介紹了Android編程中Handler用法,結(jié)合實(shí)例形式分析了Handler的功能,原理及使用技巧,需要的朋友可以參考下
    2016-01-01

最新評論

莎车县| 河北区| 庆云县| 岐山县| 基隆市| 丰都县| 台山市| 大足县| 梧州市| 聂拉木县| 沁水县| 长武县| 天峻县| 汶上县| 台江县| 黄浦区| 四川省| 仙游县| 濮阳县| 青海省| 徐闻县| 邵阳市| 五峰| 西平县| 柳河县| 民勤县| 泉州市| 嘉黎县| 玛多县| 宜丰县| 建水县| 太康县| 隆化县| 平顶山市| 辽宁省| 乡宁县| 新河县| 龙岩市| 中江县| 县级市| 鹤山市|