WheelView通過(guò)Camera和Matrix實(shí)現(xiàn)真正的3D滾輪控件

前言:

通過(guò)Camera, Matrix 3d旋轉(zhuǎn)+RecyclerView實(shí)現(xiàn)和(IOS時(shí)間地址選擇3D)滾輪控件一樣效果的WheelView繼承ViewGroup,實(shí)現(xiàn)安卓QQ上滾輪一樣的滑動(dòng)效果

更多文章請(qǐng)關(guān)注:http://www.reibang.com/u/b1cff340957c


一:先看效果圖
垂直方向的3D旋轉(zhuǎn)
水平方向的3D旋轉(zhuǎn)
不處理旋轉(zhuǎn)的SimpleDrawManager
原理圖.png
使用方式
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }  
}

dependencies {
    implementation 'com.github.youxiaochen:WheelView-3d:1.4.1'
}
布局生成WheelView方式 有默認(rèn)屬性
<chen.you.wheel.WheelView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:wheelOrientation="vertical"
    app:wheelItemCount="3"
    app:wheelItemSize="30dp"
    app:wheelGravity="center"
    app:wheelTextSize="18sp"
    app:wheelTextColor="#333333"
    app:wheelTextCenterColor="#ff00ff"
    app:wheelDividerSize="1dp"
    app:wheelDividerColor="#00ff00"
    app:wheelGradient="true"
    app:wheelDividerPadding="2dp"/>

wv.setAdapter(new WheelView.Adapter() {
    @Override
    protected String getItem(int position) {
        return "position " + position;
    }

    @Override
    protected int getItemCount() {
        return 100;
    }
});
代碼生成WheelView及擴(kuò)展方式
//需要擴(kuò)展功能時(shí)
WheelParams params = new WheelParams.Builder()
        .setOrientation(WheelParams.HORIZONTAL)
        .setItemSize(...)
        .setTextColor(...)
WheelView wv = new WheelView(context, params);
        ...
//代碼設(shè)置各種屬性
//亦可用此方式設(shè)置各屬性  
wv.getWheelParams().newBuilder().setOrientation(...) 
wv.setWheelParams(params);
//設(shè)置繪制管理, 默認(rèn)為WheelDrawManager產(chǎn)生3D旋轉(zhuǎn), 亦可設(shè)置LinearDrawManager不旋轉(zhuǎn), 也可自定義DrawManager擴(kuò)展
wv.setDrawManager(new WheelDrawManager());
//設(shè)置繪制器, 默認(rèn)為SimpleItemPainter,  也可自定義繪制器擴(kuò)展
wv.setItemPainter(...)  

二:功能分析 3D旋轉(zhuǎn)效果

WheelView的實(shí)現(xiàn)方式已經(jīng)有很多種方式, 而且網(wǎng)上也有實(shí)現(xiàn)好的旋轉(zhuǎn)效果,不過(guò)只是2D的旋轉(zhuǎn),而且要處理滑動(dòng)與單擊item事件比較復(fù)雜,真正的旋轉(zhuǎn)是要通過(guò)Matrix, Camera類來(lái)實(shí)現(xiàn),這里的Camera不是照相機(jī)里的API,Camera可以實(shí)現(xiàn)x,y,z軸的旋轉(zhuǎn),不清楚的可以去也解這些API的使用, 這里不詳細(xì)介紹, 配合RecyclerView.ItemDecoration,在每個(gè)item中將Canvas進(jìn)行3D旋轉(zhuǎn)并平移,產(chǎn)生3D視覺效果

這里拿垂直布局的一種狀態(tài)來(lái)做示例

    /**
     * 畫垂直布局時(shí)的item
     * @param c
     * @param rect
     * @param position
     * @param parentCenterX RecyclerView的中心X點(diǎn)
     * @param parentCenterY RecyclerView的中心Y點(diǎn)
     */
    void drawVerticalItem(Canvas c, Rect rect, int position, float parentCenterX, float parentCenterY) {
        int realPosition = position - itemCount;//數(shù)據(jù)中的實(shí)際位置
        float itemCenterY = rect.exactCenterY();
        float scrollOffY = itemCenterY - parentCenterY;
        float rotateDegreeX = scrollOffY * itemDegree / itemSize;//垂直布局時(shí)要以X軸為中心旋轉(zhuǎn)
        int alpha = degreeAlpha(rotateDegreeX);
        if (alpha <= 0) return;
        float rotateSinX = (float) Math.sin(Math.toRadians(rotateDegreeX));
        float rotateOffY = scrollOffY - wheelRadio * rotateSinX;//因旋轉(zhuǎn)導(dǎo)致界面視角的偏移
        //Log.i("you", "drawVerticalItem degree " + rotateDegreeX);
        //計(jì)算中心item, 優(yōu)先最靠近中心區(qū)域的為中心點(diǎn)
        boolean isCenterItem = false;
        if (!hasCenterItem) {
            isCenterItem = Math.abs(scrollOffY) <= halfItemHeight;
            if (isCenterItem) {
                centerItemPosition = realPosition;
                hasCenterItem = true;
            }
        }
        //這里是旋轉(zhuǎn)操作的核心,每個(gè)item在旋轉(zhuǎn)成弧時(shí)寇漫,都要將item的中心在旋轉(zhuǎn)后給人的視覺上的偏移計(jì)算好
        c.save();
        c.translate(0.0f, -rotateOffY);//因旋轉(zhuǎn)導(dǎo)致界面視角的偏移
        camera.save();

        //旋轉(zhuǎn)時(shí)離視角的z軸方向也會(huì)變化,先移動(dòng)Z軸再旋轉(zhuǎn)
        float z = (float) (wheelRadio * (1 - Math.abs(Math.cos(Math.toRadians(rotateDegreeX)))));
        camera.translate(0, 0, z);


        camera.rotateX(-rotateDegreeX);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-translateX, -itemCenterY);
        matrix.postTranslate(translateX, itemCenterY);
        c.concat(matrix);
        drawItem(c, rect, realPosition, alpha, isCenterItem, true);
        c.restore();
    }

到這里基本已經(jīng)實(shí)現(xiàn)了每個(gè)item距離中心點(diǎn)的旋轉(zhuǎn)效果,接下來(lái)就是添加WheelView顯示的數(shù)量在RecyclerView頭與尾部的空的item

最后附上源碼 https://github.com/youxiaochen/WheelView-3d

總結(jié):

WheelView具體使用方法,示例代碼中都有詳細(xì)介紹

更多文章請(qǐng)關(guān)注:http://www.reibang.com/u/b1cff340957c

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捍歪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子茫舶,更是在濱河造成了極大的恐慌终议,老刑警劉巖旧巾,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舒裤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)宜鸯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門人灼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人顾翼,你說(shuō)我怎么就攤上這事∧卫幔” “怎么了适贸?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)涝桅。 經(jīng)常有香客問我拜姿,道長(zhǎng),這世上最難降的妖魔是什么冯遂? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任蕊肥,我火速辦了婚禮,結(jié)果婚禮上蛤肌,老公的妹妹穿的比我還像新娘壁却。我一直安慰自己,他們只是感情好裸准,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布展东。 她就那樣靜靜地躺著,像睡著了一般炒俱。 火紅的嫁衣襯著肌膚如雪盐肃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天权悟,我揣著相機(jī)與錄音砸王,去河邊找鬼。 笑死峦阁,一個(gè)胖子當(dāng)著我的面吹牛谦铃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拇派,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼荷辕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了件豌?” 一聲冷哼從身側(cè)響起疮方,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎茧彤,沒想到半個(gè)月后骡显,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年惫谤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了壁顶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡溜歪,死狀恐怖若专,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蝴猪,我是刑警寧澤调衰,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站自阱,受9級(jí)特大地震影響嚎莉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沛豌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一趋箩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧加派,春花似錦叫确、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至醉旦,卻和暖如春饶米,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背车胡。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工檬输, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人匈棘。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓丧慈,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親主卫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逃默,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,072評(píng)論 25 707
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,755評(píng)論 22 665
  • 天之涯 海之角 云散了 潮退了 聽得到一聲嘆 哀怨纏綿 見得到淚痕濕 心又涼薄 相見亦無(wú)事 別后長(zhǎng)憶君 相隔三千里...
    七七ii閱讀 298評(píng)論 0 0
  • 張清的日精進(jìn)第61天 體驗(yàn)入 今天是四季度醫(yī)療部啟動(dòng)會(huì),內(nèi)部客戶已經(jīng)全員確認(rèn)簇搅,各崗位業(yè)績(jī)數(shù)額完域,考核內(nèi)容,考核標(biāo)準(zhǔn)已...
    kiyoi2017閱讀 162評(píng)論 0 4