溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android如何使用裸眼3D效果View控件

發(fā)布時(shí)間:2021-08-17 09:05:31 來(lái)源:億速云 閱讀:119 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下Android如何使用裸眼3D效果View控件,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

描述:這是一個(gè)裸眼3D效果的控件View。

控件效果如下:

Android如何使用裸眼3D效果View控件

實(shí)現(xiàn)功能:

  1. 實(shí)現(xiàn)三層圖片疊加效果(裸眼3D效果)

  2. 可設(shè)置每層圖片移動(dòng)速率

  3. 可設(shè)置每層圖片移動(dòng)的限制度數(shù)

  4. 可直接設(shè)置圖片或引入圖片

設(shè)計(jì)核心:

主要的設(shè)計(jì)核心是依賴于傳感器對(duì)手機(jī)晃動(dòng)的監(jiān)聽(重力感應(yīng)監(jiān)聽器),對(duì)每層圖片進(jìn)行不同的移動(dòng),實(shí)現(xiàn)仿3D效果。

核心代碼:

SensorLayout 用以監(jiān)聽傳感器

import android.content.Context;
import android.content.res.TypedArray;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.Scroller;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.ui.design.R;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 傳感器監(jiān)聽
* author tangxianfeng
* created  2021.8.15
**/
public class SensorLayout extends FrameLayout implements SensorEventListener {
    private final SensorManager mSensorManager;
    private float[] mAccelerateValues;
    private float[] mMagneticValues;
    private final Scroller mScroller;
    private double mDegreeYMin = -50;//最小偏移度數(shù)  Y
    private double mDegreeYMax = 50;//最大偏移度數(shù)  Y
    private double mDegreeXMin = -50;//最小偏移度數(shù)  X
    private double mDegreeXMax = 50;//最大偏移度數(shù)  X
    private static final double MOVE_DISTANCE_X = 50;//X軸移動(dòng)偏移量 實(shí)際偏移為MOVE_DISTANCE_X*acclerateratio
    private static final double MOVE_DISTANCE_Y = 50;//Y軸移動(dòng)偏移量 實(shí)際偏移為MOVE_DISTANCE_Y*acclerateratio
    private float acclerateratio = 1;//偏移加速的倍率 可以通過設(shè)置此倍率改變偏移速度
    private final float[] values = new float[3];//包含 x,y,z的偏移量
    private final float[] Sensororientation = new float[9];//旋轉(zhuǎn)矩陣

    public SensorLayout(@NonNull Context context) {
        this(context, null);
    }

    public SensorLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SensorLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mScroller = new Scroller(context);
        if (attrs != null) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SensorLayoutStyle);
            acclerateratio = typedArray.getFloat(R.styleable.SensorLayoutStyle_AccelerateRatio, 1);
        }
        mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
        if (mSensorManager != null) {
            Sensor accelerateSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            // 地磁場(chǎng)傳感器
            Sensor magneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
            mSensorManager.registerListener(this, accelerateSensor, SensorManager.SENSOR_DELAY_GAME);
            mSensorManager.registerListener(this, magneticSensor, SensorManager.SENSOR_DELAY_GAME);
        }
    }


    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            mAccelerateValues = event.values;
        }
        if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            mMagneticValues = event.values;
        }

        if (mMagneticValues != null && mAccelerateValues != null)
            SensorManager.getRotationMatrix(Sensororientation, null, mAccelerateValues, mMagneticValues);
        SensorManager.getOrientation(Sensororientation, values);
        // x軸的偏轉(zhuǎn)角度
        double degreeX = (float) Math.toDegrees(values[1]);
        // y軸的偏轉(zhuǎn)角度
        double degreeY = (float) Math.toDegrees(values[2]);
        int scrollX = mScroller.getFinalX();
        int scrollY = mScroller.getFinalY();
        if (degreeY <= 0 && degreeY > mDegreeYMin) {
            scrollX = (int) (degreeY / Math.abs(mDegreeYMin) * MOVE_DISTANCE_X * acclerateratio);
        } else if (degreeY > 0 && degreeY < mDegreeYMax) {
            scrollX = (int) (degreeY / Math.abs(mDegreeYMax) * MOVE_DISTANCE_X * acclerateratio);
        }
        if (degreeX <= 0 && degreeX > mDegreeXMin) {
            scrollY = (int) (degreeX / Math.abs(mDegreeXMin) * MOVE_DISTANCE_Y * acclerateratio);
        } else if (degreeX > 0 && degreeX < mDegreeXMax) {
            scrollY = (int) (degreeX / Math.abs(mDegreeXMax) * MOVE_DISTANCE_Y * acclerateratio);
        }
        smoothScroll(scrollX, scrollY);
    }


    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    //移動(dòng)
    public void smoothScroll(int destX, int destY) {
        int scrollY = getScrollY();
        int delta = destY - scrollY;
        mScroller.startScroll(destX, scrollY, 0, delta, 200);
        invalidate();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

    //解綁監(jiān)聽
    public void unregister() {
        mSensorManager.unregisterListener(this);
    }

    public void setDegree(double degreeYMin,double degreeYMax,double degreeXMin,double degreeXMax) {
        mDegreeYMin = degreeYMin;
        mDegreeYMax=degreeYMax;
        degreeXMax=degreeYMax;
        degreeXMin=degreeXMin;
    }

    public void setAcclerateratio(float acclerateratio) {
        this.acclerateratio = acclerateratio;
    }

    @IntDef({DIRECTION_LEFT, DIRECTION_RIGHT})
    @Retention(RetentionPolicy.SOURCE)
    @Target(ElementType.PARAMETER)
    public @interface ADirection {

    }

    public static final int DIRECTION_LEFT = 1;
    public static final int DIRECTION_RIGHT = -1;
}

Sensor3DView 三層視圖封裝

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

import com.bumptech.glide.Glide;
import com.ui.design.R;
/**
* author tangxianfeng
* created  2021.8.15
**/
public class Sensor3DView extends LinearLayout {

    private SensorLayout sensorforeground;//最上層傳感器View
    private SensorLayout sensorbackground;//最底層傳感器View
    private SensorLayout sensormid;//中間層傳感器View

    private ImageView foregroundimg;//最上層圖片
    private ImageView backgroundimg;//底層圖片
    private ImageView midimg;//中間層圖片

    private Context mContext;

    public Sensor3DView(Context context) {
        super(context);
        this.mContext = context;
    }

    public Sensor3DView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        View inflate = LayoutInflater.from(getContext()).inflate(R.layout.sensor3d_item, this);
        this.mContext = context;
        initView(inflate);

        if (attrs != null) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.Sensor3DViewStyle);
            float forgroundacclerateratio = typedArray.getFloat(R.styleable.Sensor3DViewStyle_foregroundAccelerateRatio, 1);
            float backgroundacclerateratio = typedArray.getFloat(R.styleable.Sensor3DViewStyle_backgroundAccelerateRatio, 1);
            float midacclerateratio = typedArray.getFloat(R.styleable.Sensor3DViewStyle_midAccelerateRatio, 1);
            setAllImg(typedArray.getResourceId(R.styleable.Sensor3DViewStyle_backgrounddrawable,1),typedArray.getResourceId(R.styleable.Sensor3DViewStyle_middrawable,1),typedArray.getResourceId(R.styleable.Sensor3DViewStyle_foregrounddrawable,1));
            setAllratio(backgroundacclerateratio, midacclerateratio, forgroundacclerateratio);
        }
    }

    private void initView(View inflate) {
        sensorforeground = inflate.findViewById(R.id.sensorforeground);
        sensorbackground = inflate.findViewById(R.id.sensorbackground);
        sensormid = inflate.findViewById(R.id.sensormid);
        midimg = inflate.findViewById(R.id.midimg);
        backgroundimg = inflate.findViewById(R.id.backgroundimg);
        foregroundimg = inflate.findViewById(R.id.foregroundimg);
    }

    //加載三張圖片
    public void setAllImg(Object backgroundurl, Object midurl, Object foregroundurl) {
        Glide.with(mContext).load(backgroundurl).into(backgroundimg);
        Glide.with(mContext).load(midurl).into(midimg);
        Glide.with(mContext).load(foregroundurl).into(foregroundimg);
    }

    //設(shè)置移動(dòng)速度
    public void setAllratio(float backgroundratio, float midratio, float foregroundratio) {
        sensorbackground.setAcclerateratio(backgroundratio);
        sensormid.setAcclerateratio(midratio);
        sensorforeground.setAcclerateratio(foregroundratio);
    }

    //設(shè)置限制角度
    public void setDegree(float MinX,float MinY,float MaxX,float MaxY,View3DLayer layer){
        if (MinX>=MaxX||MinY>=MaxY){
            return;
        }
        switch (layer){
            case all:
                setDegree(MinY,MaxY,MinX,MaxX,sensorforeground);
                setDegree(MinY,MaxY,MinX,MaxX,sensormid);
                setDegree(MinY,MaxY,MinX,MaxX,sensorbackground);
                break;
            case mid:
                setDegree(MinY,MaxY,MinX,MaxX,sensormid);
                break;
            case background:
                setDegree(MinY,MaxY,MinX,MaxX,sensorbackground);
                break;
            case foreground:
                setDegree(MinY,MaxY,MinX,MaxX,sensorforeground);
                break;
        }
    }

    //sensorLayout 設(shè)置限制角度
    private void setDegree(float MinY,float MaxY,float MinX,float MaxX,SensorLayout sensorLayout){
        sensorLayout.setDegree(MinY,MaxY,MinX,MaxX);
    }
    @Override
    public void destroyDrawingCache() {
        super.destroyDrawingCache();
        sensorbackground.unregister();
        sensormid.unregister();
        sensorforeground.unregister();
    }
    public enum View3DLayer{
        foreground,
        background,
        mid,
        all
    }
}

styles.xml

<!--3D裸眼效果-->
    <declare-styleable name="SensorLayoutStyle">
        <attr name="AccelerateRatio" format="float" />
    </declare-styleable>


    <!--3D裸眼效果集合View-->
    <declare-styleable name="Sensor3DViewStyle">
        <attr name="foregroundAccelerateRatio" format="float" />
        <attr name="backgroundAccelerateRatio" format="float" />
        <attr name="midAccelerateRatio" format="float" />
        <attr name="foregrounddrawable" format="reference" />
        <attr name="backgrounddrawable" format="reference" />
        <attr name="middrawable" format="reference" />
    </declare-styleable>

使用示例:

直接引用到layout文件中便可,或者可通過代碼設(shè)置其他屬性。

 <com.ui.design.view.sensor3D.view.Sensor3DView
        android:id="@+id/sensor3Dview"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
        app:foregrounddrawable="@drawable/forground3d"
        app:backgrounddrawable="@drawable/background3d"
        app:middrawable="@drawable/mid3d"
        app:foregroundAccelerateRatio="4.0"
        app:backgroundAccelerateRatio="-2.0"
        app:midAccelerateRatio="1.0"/>

以上是“Android如何使用裸眼3D效果View控件”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI