View实现3D效果

View实现3D效果1. 利用MotionLayout实现 一个简单的效果: 2. 封装View 主要代码 传感器初始化: 计算移动距离: 滑动: 属性配置: 在布局中引入: 最终效果: 4. 问题 不知道为啥有时候会莫

上次有文章介绍了利用传感器实现3D效果,根据加速度和重力传感器,计算xy偏移值,然后在移动view。

1. 利用MotionLayout实现

最开始想到的是用motionlayout也可以同样实现,但是最后发现我错了,motionlayout设置的view路径是固定的,无法在xy轴上自由移动。

一个简单的效果:
1.gif

2. 封装View

利用自定义ViewGroup实现,直接在布局中引用就行了

主要代码

传感器初始化:

//获取传感器XYZ值
    private var mAcceleValues : FloatArray ?= null
    private var mMageneticValues : FloatArray ?= null
    private val listener = object : SensorEventListener {
        override fun onSensorChanged(event: SensorEvent?) {
            if (event?.sensor?.type == Sensor.TYPE_ACCELEROMETER) {
                mAcceleValues = event.values
                //log("x:${event.values[0]},y:${event.values[1]},z:${event.values[2]}")
            }
            if (event?.sensor?.type == Sensor.TYPE_MAGNETIC_FIELD) {
                mMageneticValues = event.values
            }
            if (mAcceleValues==null || mMageneticValues==null) return

            val values = FloatArray(3)
            val R = FloatArray(9)
            SensorManager.getRotationMatrix(R, null, mAcceleValues, mMageneticValues);
            SensorManager.getOrientation(R, values);

            //val z = values[0].toDouble()
            // x轴的偏转角度
            //val x = Math.toDegrees(values[1].toDouble()).toFloat()
            // y轴的偏转角度
            //val y = Math.toDegrees(values[2].toDouble()).toFloat()

            val degreeZ = Math.toDegrees(values[0].toDouble()).toInt()
            val degreeX = Math.toDegrees(values[1].toDouble()).toInt()
            val degreeY = Math.toDegrees(values[2].toDouble()).toInt()
            log("x:${degreeX},y:${degreeY},z:${degreeZ}")
            calculateScroll(degreeX, degreeY, degreeZ)
        }

        override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
        }
    }



    //传感器初始化
    private var hasInit = false
    private fun initSensor(){
        if (hasInit) return
        log("initSensor")
        val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager

        // 重力传感器
        val acceleSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
        sensorManager.registerListener(listener, acceleSensor, SensorManager.SENSOR_DELAY_GAME)

        // 地磁场传感器
        val magneticSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
        sensorManager.registerListener(listener, magneticSensor, SensorManager.SENSOR_DELAY_GAME)

        hasInit = true
    }

计算移动距离:

private fun calculateScroll(x: Int, y: Int, z: Int) {
        var deltaY = 0
        var deltaX = 0

        //除去一下特殊的角度
        //if (abs(x)==180 || abs(x)==90 || abs(y)==180 || abs(y)==90) return
        //if (x !in -90 until 45) return

        if (abs(z) > 90){
            if (y in -180 until 0){
                //从右向左旋转
                //x值增加
                deltaX = abs(((y / 180.0) * slideDistance).toInt())
            }else if (y in 0 until 180){
                //从左向右旋转
                deltaX = -abs(((y / 180.0) * slideDistance).toInt())
            }
        }

        if (x in -90 until 0){
            deltaY = abs((((x) / 180.0) * slideDistance).toInt())
        }else if (x in 0 until 90){
            deltaY = -abs((((x) / 180.0) * slideDistance).toInt())
        }

        if (abs(deltaX) < 5) deltaX=0
        if (abs(deltaY) < 5) deltaY=0
       
        log("onSensorChanged,scrollX:${deltaX},scrollY:${deltaY},x:${x} y:${y}")
    }

滑动:

 scroller.startScroll(deltaX,deltaY, (this.x+deltaX).toInt(),(this.y+deltaY).toInt(),1000)
override fun computeScroll() {
        super.computeScroll()
        //判断Scroller是否执行完毕
        if (scroller.computeScrollOffset()) {
            val slideX = scroller.currX
            val slideY = scroller.currY

            val bottomSlideX = slideX/3
            val bottomSlideY = slideY/3

            val middleSlideX = slideX/2
            val middleSlideY = slideY/2

            val topSlideX = -slideX
            val topSlideY = -slideY

            bottomImageView?.layout(0+bottomSlideX,0+bottomSlideY,measuredWidth+bottomSlideX,measuredHeight+bottomSlideY)
            //middleImageView?.layout(middleLeft+middleSlideX,middleTop+middleSlideY,middleRight+middleSlideX,middleBottom+middleSlideY)
            topImageView?.layout(topLeft+topSlideX,topTop+topSlideY,topRight+topSlideX,topBottom+topSlideY)

            /*(bottomImageView as View).scrollTo( scroller.currX, scroller.currY )*/
            //通过重绘来不断调用computeScroll
            invalidate()
        }
    }


属性配置:

<declare-styleable name="layout3d">
    <!--上中下层资源文件-->
    <attr name="TopLayer" format="reference" />
    <attr name="MiddleLayer" format="reference" />
    <attr name="BottomLayer" format="reference" />

    <!--上中下层滑动距离-->
    <attr name="SlideDistance" format="dimension"/>

    <!--上中下层是否滑动-->
    <attr name="TopSlidingEnable" format="boolean"/>
    <attr name="MiddleSlidingEnable" format="boolean"/>
    <attr name="BottomSlidingEnable" format="boolean"/>


    <!--中层图片资源坐标设置-->
    <attr name="MiddleLayerTop" format="dimension"/>
    <attr name="MiddleLayerBottom" format="dimension"/>
    <attr name="MiddleLayerLeft" format="dimension"/>
    <attr name="MiddleLayerRight" format="dimension"/>

    <!--上层图片资源坐标设置-->
    <attr name="TopLayerTop" format="dimension"/>
    <attr name="TopLayerBottom" format="dimension"/>
    <attr name="TopLayerLeft" format="dimension"/>
    <attr name="TopLayerRight" format="dimension"/>

</declare-styleable>

“`

在布局中引入:

<com.example.montionlayout3d.view.Layout3D
    android:id="@+id/vg3D"
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:background="@color/titi"
    app:TopLayer="@drawable/circle"
    app:MiddleLayer="@drawable/star1"
    app:BottomLayer="@drawable/back"
    layout3d:MiddleLayerTop="30dp"
    layout3d:MiddleLayerBottom="70dp"
    layout3d:MiddleLayerLeft="300dp"
    layout3d:MiddleLayerRight="340dp"
    layout3d:TopLayerTop="50dp"
    layout3d:TopLayerBottom="200dp"
    layout3d:TopLayerLeft="20dp"
    layout3d:TopLayerRight="170dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

最终效果:

2.gif

3.gif

4. 问题

不知道为啥有时候会莫名抽搐,移动的不是很顺滑。。。。

实现效果不太好,小问题还很多,不建议使用😥😥

求大佬指点

5. 项目地址

今天的文章View实现3D效果分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/18110.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注