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

วิธีตรวจจับการเปลี่ยนทิศทางหน้าจอ (Orientation) ใน Android

ภาพรวม

บทความนี้สาธิตวิธีตรวจจับการเปลี่ยนแปลงทิศทางหน้าจอ (Portrait ↔ Landscape) ใน Android มี 2 วิธีหลัก: 1) Override onConfigurationChanged() พร้อม android:configChanges ใน Manifest (แอปจัดการเอง) 2) ให้ระบบ Recreate Activity (Default behavior) และตรวจสอบใน onCreate()

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

สร้างโปรเจกต์ Android ใหม่ใน Android Studio

ขั้นตอนที่ 2: ออกแบบ Layout (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:textSize="24sp"
        android:textStyle="bold" />

</LinearLayout>

วิธีที่ 1: จัดการเองด้วย configChanges (ไม่ Recreate Activity)

AndroidManifest.xml - เพิ่ม configChanges

<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

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

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        // ตรวจสอบ Orientation
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            Toast.makeText(this, "📱 Landscape Mode (แนวนอน)", Toast.LENGTH_SHORT).show();
            // ปรับ Layout, Visibility, หรือ Logic สำหรับ Landscape
            updateUIForLandscape();
        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
            Toast.makeText(this, "📱 Portrait Mode (แนวตั้ง)", Toast.LENGTH_SHORT).show();
            // ปรับ Layout, Visibility, หรือ Logic สำหรับ Portrait
            updateUIForPortrait();
        }

        // ตรวจสอบการเปลี่ยนแปลงอื่นๆ
        if ((newConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) 
                == Configuration.SCREENLAYOUT_SIZE_LARGE) {
            // หน้าจอขนาดใหญ่ (Tablet, Foldable)
        }
    }

    private void updateUIForLandscape() {
        // ตัวอย่าง: ซ่อน Toolbar, แสดง 2 Column, ปรับขนาด Font
    }

    private void updateUIForPortrait() {
        // ตัวอย่าง: แสดง Toolbar, 1 Column, ปรับขนาด Font
    }
}

วิธีที่ 2: ให้ระบบ Recreate Activity (Default - แนะนำสำหรับมือใหม่)

AndroidManifest.xml - ไม่ต้องเพิ่ม configChanges

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

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

        // ตรวจสอบ Orientation ปัจจุบัน
        int orientation = getResources().getConfiguration().orientation;
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            Toast.makeText(this, "Landscape (onCreate)", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Portrait (onCreate)", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // ไม่จำเป็นต้องทำอะไร เพราะ Activity จะถูก Destroy/Recreate
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // บันทึกข้อมูลที่ต้องการเก็บไว้ (Scroll Position, Form Data, etc.)
        outState.putString("key", "value");
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        // เรียกคืนข้อมูล
        String value = savedInstanceState.getString("key");
    }
}

Layout แยกตาม Orientation (Best Practice)

สร้างไฟล์ Layout แยกในโฟลเดอร์ res/layout-land/:

  • res/layout/activity_main.xml - Portrait Layout
  • res/layout-land/activity_main.xml - Landscape Layout

ระบบจะเลือก Layout อัตโนมัติเมื่อหมุนหน้าจอ (ถ้าไม่ใช้ configChanges)

การจัดการกับ Foldable / Multi-window (Modern Android)

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    
    // ตรวจสอบ Foldable State
    if (newConfig.screenLayout != 0) {
        int screenLayout = newConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
        // SMALL, NORMAL, LARGE, XLARGE
    }
    
    // ตรวจสอบ Window Metrics (API 30+)
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
        android.view.WindowMetrics metrics = getWindowManager().getCurrentWindowMetrics();
        android.graphics.Insets insets = metrics.getWindowInsets()
            .getInsetsIgnoringVisibility(android.view.WindowInsets.Type.systemBars());
        // คำนวณพื้นที่ใช้งานจริง
    }
}

ตารางเปรียบเทียบ 2 วิธี

ด้านconfigChanges (Manual)Default Recreate
Performanceดีกว่า (ไม่ Recreate)ช้ากว่า (Destroy/Create)
Complexityสูง (จัดการ View/State เอง)ต่ำ (ระบบจัดการ)
State ManagementManual (Retain Instance)Auto (onSaveInstanceState)
Layout SwitchingManual (setContentView)Auto (layout-land folder)
สถานการณ์เหมาะสมVideo Player, Camera, Game, MapForm, List, General App

Best Practices

  • Default: ให้ระบบ Recreate (วิธีที่ 2) - เรียบง่าย ปลอดภัย
  • ใช้ configChanges เมื่อ: Video Player, Camera Preview, OpenGL Games, WebView ที่ซับซ้อน
  • ViewModel + LiveData: ใช้ Architecture Components เพื่อเก็บ State ระหว่าง Rotation ได้อัตโนมัติ
  • Testing: ทดสอบหมุนหน้าจอซ้ำๆ (Don't keep activities ใน Developer Options)