Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีใช้ Gravity View ใน Android

Gravity View: แสดงภาพ 360 องศา/Parallax ด้วย Sensor

Gravity View เป็นไลบรารีที่ใช้ Sensor (Accelerometer, Gyroscope) ของอุปกรณ์ Android เพื่อให้ผู้ใช้มองเห็นภาพกว้าง/360 องศาโดยการเอียงอุปกรณ์ เหมาะสำหรับ Virtual Tour, Product Showcase, Panorama Viewer

⚠️ สถานะไลบรารี

ไลบรารี co.gofynd.library:gravity-view:1.0 ดูเหมือนจะไม่ได้รับการอัปเดตนาน (Last update ~2018) และอาจไม่รองรับ Android ใหม่ๆ แนะนำให้พิจารณา:

  • Google Scene Viewer / ARCore สำหรับ AR/3D
  • PanoramaGL หรือ ViroCore สำหรับ Panorama/360
  • เขียนเองด้วย SensorManager + OpenGL ES เพื่อควบคุมได้เต็มที่

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

Android Studio → File → New Project → Empty Activity

ขั้นตอนที่ 2: build.gradle (Module) - เพิ่ม Dependency

dependencies {
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    // ไลบรารี Gravity View (เก่า อาจต้องใช้ JitPack)
    implementation 'com.github.gofynd:gravity-view:1.0' 
    // หรือถ้าไม่หาเจอ ให้ลอง implementation 'co.gofynd.library:gravity-view:1.0'
}

ใน Project-level build.gradle ต้องมี maven { url 'https://jitpack.io' }

ขั้นตอนที่ 3: Layout - activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="none"
        android:overScrollMode="never">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/panorama_image" />

    </HorizontalScrollView>

</RelativeLayout>

เตรียมภาพ: ใส่ภาพ Panorama (กว้างมาก ความสูงเท่าจอ) ใน res/drawable/panorama_image.jpg หรือ res/drawable-nodpi/

ขั้นตอนที่ 4: MainActivity.java

package com.example.gravityviewdemo;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.ImageView;
import co.gofynd.gravityview.GravityView;

public class MainActivity extends AppCompatActivity {

    private GravityView gravityView;
    private ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = findViewById(R.id.imageView);
        gravityView = GravityView.getInstance(this);

        // ตรวจสอบว่าอุปกรณ์รองรับ Sensor ที่จำเป็นหรือไม่
        boolean isSupported = gravityView.deviceSupported();
        
        if (isSupported) {
            gravityView
                    .setImage(imageView, R.drawable.panorama_image)
                    .center(); // เริ่มที่กึ่งกลาง
        } else {
            imageView.setImageResource(R.drawable.panorama_image);
            // Fallback: ใช้ HorizontalScrollView ธรรมดา
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (gravityView != null) {
            gravityView.registerListener(); // เริ่มฟัง Sensor
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (gravityView != null) {
            gravityView.unRegisterListener(); // หยุดฟัง Sensor (ประหยัดแบต)
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (gravityView != null) {
            gravityView.destroy(); // ทำความสะอาด
        }
    }
}

การทำงานของ Gravity View

  1. Sensor Fusion: รวม Accelerometer + Gyroscope (ถ้ามี) เพื่อคำนวณ Orientation
  2. Image Mapping: แมปภาพกว้างลงบน Viewport ของหน้าจอ
  3. Parallax Effect: เลื่อนภาพตามมุมเอียงของอุปกรณ์

การเขียนเอง (Custom Implementation) - แนะนำสำหรับ Production

หากไลบรารีเก่าไม่ทำงาน ให้เขียนเองด้วย SensorManager:

public class CustomGravityView {
    private SensorManager sensorManager;
    private Sensor accelerometer, magnetometer;
    private float[] rotationMatrix = new float[9];
    private float[] orientation = new float[3];
    private ImageView imageView;
    private int imageWidth, screenWidth;
    private float maxScrollX;

    public CustomGravityView(Context context, ImageView imageView) {
        this.imageView = imageView;
        sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        magnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
    }

    public void register() {
        sensorManager.registerListener(sensorEventListener, accelerometer, SensorManager.SENSOR_DELAY_GAME);
        sensorManager.registerListener(sensorEventListener, magnetometer, SensorManager.SENSOR_DELAY_GAME);
    }

    public void unregister() {
        sensorManager.unregisterListener(sensorEventListener);
    }

    private final SensorEventListener sensorEventListener = new SensorEventListener() {
        float[] gravity = new float[3];
        float[] geomagnetic = new float[3];

        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                gravity = event.values.clone();
            } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                geomagnetic = event.values.clone();
            }

            if (SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic)) {
                SensorManager.getOrientation(rotationMatrix, orientation);
                // orientation[0] = Azimuth (Z-axis), orientation[1] = Pitch (X-axis), orientation[2] = Roll (Y-axis)
                
                float azimuth = orientation[0]; // -PI to PI
                float scrollX = (azimuth / (float)Math.PI) * maxScrollX; // Map to scroll
                
                imageView.post(() -> imageView.setScrollX((int) scrollX));
            }
        }

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

สรุป

Gravity View ให้เอฟเฟกต์ Parallax/360 View ได้ง่าย แต่ไลบรารีเก่าอาจมีปัญหาเข้ากันไม่ได้กับ Android ใหม่ แนะนำให้เขียนเองด้วย SensorManager หรือใช้ไลบรารีสมัยใหม่เช่น ViroCore/ARCore เพื่อความเสถียรและฟีเจอร์มากกว่า