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

前言:

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

更多文章請關(guān)注:http://www.itdecent.cn/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及擴展方式
//需要擴展功能時
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擴展
wv.setDrawManager(new WheelDrawManager());
//設(shè)置繪制器, 默認(rèn)為SimpleItemPainter,  也可自定義繪制器擴展
wv.setItemPainter(...)  

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

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

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

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

        //旋轉(zhuǎn)時離視角的z軸方向也會變化,先移動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)實現(xiàn)了每個item距離中心點的旋轉(zhuǎn)效果,接下來就是添加WheelView顯示的數(shù)量在RecyclerView頭與尾部的空的item

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

總結(jié):

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

更多文章請關(guān)注:http://www.itdecent.cn/u/b1cff340957c

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容