WheelView通过Camera和Matrix实现真正的3D滚轮控件

前言:

通过Camera, Matrix 3d旋转+RecyclerView实现和(IOS时间地址选择3D)滚轮控件一样效果的WheelView继承ViewGroup,实现安卓QQ上滚轮一样的滑动效果

更多文章请关注:http://www.jianshu.com/u/b1cff340957c


一:先看效果图
垂直方向的3D旋转
水平方向的3D旋转
不处理旋转的SimpleDrawManager
原理图.png
使用方式
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }  
}

dependencies {
    implementation 'com.github.youxiaochen:WheelView-3d:1.4.1'
}
布局生成WheelView方式 有默认属性
<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);
        ...
//代码设置各种属性
//亦可用此方式设置各属性  
wv.getWheelParams().newBuilder().setOrientation(...) 
wv.setWheelParams(params);
//设置绘制管理, 默认为WheelDrawManager产生3D旋转, 亦可设置LinearDrawManager不旋转, 也可自定义DrawManager扩展
wv.setDrawManager(new WheelDrawManager());
//设置绘制器, 默认为SimpleItemPainter,  也可自定义绘制器扩展
wv.setItemPainter(...)  

二:功能分析 3D旋转效果

WheelView的实现方式已经有很多种方式, 而且网上也有实现好的旋转效果,不过只是2D的旋转,而且要处理滑动与单击item事件比较复杂,真正的旋转是要通过Matrix, Camera类来实现,这里的Camera不是照相机里的API,Camera可以实现x,y,z轴的旋转,不清楚的可以去也解这些API的使用, 这里不详细介绍, 配合RecyclerView.ItemDecoration,在每个item中将Canvas进行3D旋转并平移,产生3D视觉效果

这里拿垂直布局的一种状态来做示例

    /**
     * 画垂直布局时的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;//数据中的实际位置
        float itemCenterY = rect.exactCenterY();
        float scrollOffY = itemCenterY - parentCenterY;
        float rotateDegreeX = scrollOffY * itemDegree / itemSize;//垂直布局时要以X轴为中心旋转
        int alpha = degreeAlpha(rotateDegreeX);
        if (alpha <= 0) return;
        float rotateSinX = (float) Math.sin(Math.toRadians(rotateDegreeX));
        float rotateOffY = scrollOffY - wheelRadio * rotateSinX;//因旋转导致界面视角的偏移
        //Log.i("you", "drawVerticalItem degree " + rotateDegreeX);
        //计算中心item, 优先最靠近中心区域的为中心点
        boolean isCenterItem = false;
        if (!hasCenterItem) {
            isCenterItem = Math.abs(scrollOffY) <= halfItemHeight;
            if (isCenterItem) {
                centerItemPosition = realPosition;
                hasCenterItem = true;
            }
        }
        //这里是旋转操作的核心,每个item在旋转成弧时,都要将item的中心在旋转后给人的视觉上的偏移计算好
        c.save();
        c.translate(0.0f, -rotateOffY);//因旋转导致界面视角的偏移
        camera.save();

        //旋转时离视角的z轴方向也会变化,先移动Z轴再旋转
        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();
    }

到这里基本已经实现了每个item距离中心点的旋转效果,接下来就是添加WheelView显示的数量在RecyclerView头与尾部的空的item

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

总结:

WheelView具体使用方法,示例代码中都有详细介绍

更多文章请关注:http://www.jianshu.com/u/b1cff340957c

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 176,370评论 25 709
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 47,047评论 22 665
  • 天之涯 海之角 云散了 潮退了 听得到一声叹 哀怨缠绵 见得到泪痕湿 心又凉薄 相见亦无事 别后长忆君 相隔三千里...
    七七ii阅读 2,338评论 0 0
  • 张清的日精进第61天 体验入 今天是四季度医疗部启动会,内部客户已经全员确认,各岗位业绩数额,考核内容,考核标准已...
    kiyoi2017阅读 1,319评论 0 4

友情链接更多精彩内容