Làm cách nào để phát hiện sự thay đổi hướng trong bố cục trong Android?


110

Tôi vừa triển khai tính năng thay đổi hướng - ví dụ: khi bố cục thay đổi từ dọc sang ngang (hoặc ngược lại). Làm thế nào tôi có thể phát hiện khi sự kiện thay đổi hướng kết thúc.

Các OrientationEventListenerkhông làm việc. Làm cách nào để nhận thông báo về các sự kiện thay đổi hướng bố cục?


Trong trường hợp của tôi, onCreate () được gọi khi hướng thay đổi.
Josiel Novaes

Câu trả lời:


293

Sử dụng phương thức onConfigurationChanged của Activity. Xem đoạn mã sau:

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

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}

Bạn cũng phải chỉnh sửa cho phù hợp trong tệp kê khai của bạn để bao gồm android: configChanges Chỉ cần xem mã bên dưới:

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">

LƯU Ý: với Android 3.2 (API cấp 13) trở lên, "kích thước màn hình" cũng thay đổi khi thiết bị chuyển đổi giữa hướng dọc và ngang. Do đó, nếu bạn muốn ngăn thời gian chạy khởi động lại do thay đổi hướng khi phát triển cho API cấp 13 trở lên, bạn phải khai báo android: configChanges = "direction | screenSize" cho API cấp 13 trở lên .

Hy vọng điều này sẽ giúp bạn... :)


3
Điều này là tốt, nhưng nó ngay lập tức tải bố cục xml trong thư mục layout-land, nó sử dụng các tệp bố cục xml dọc.
Lập trình viên

22
Aztec Coder, khi bạn bao gồm "android: configChanges =" direction ", bạn đang tuyên bố rằng bạn sẽ xử lý thay đổi hướng, điều này có nghĩa là hoạt động của bạn sẽ không được tạo lại khi bạn chuyển sang chế độ ngang. Thay vào đó, onConfigurationChanged được gọi. Nếu điều này là không mong muốn , bạn có thể sử dụng một biến để ghi nhớ hướng hoạt động của mình và mỗi khi bạn tiếp tục, hãy bật Tạm dừng (ví dụ) để kiểm tra xem hướng đó có còn giống nhau không.
Elena

14
Nếu bạn đang phát triển cho API cấp 13 (3.2) trở lên, bạn nên chỉ định android: configChanges = "direction | screenSize", nếu không onConfigurationChanged sẽ không được gọi: developer.android.com/guide/topics/resources/…
Arne

1
Xin chào, tôi đang xây dựng ứng dụng của mình với API 10 (Android 2.3.3). Và nó nhận ra hướng hoàn hảo khi tôi sử dụng android: configChanges = "direction | keyboardHidden". Nhưng Nexus S chạy Android 4.1.2 của tôi không phát hiện thấy sự thay đổi hướng. Tôi nên làm gì?
Karthik Andhamil

2
sử dụng android: configChanges = "định hướng | screenSize" thay vì android: configChanges = "định hướng | keyboardHidden" trong tệp kê khai của bạn và kiểm tra ... !!!
Dinesh Sharma

15

Để tải bố cục trong thư mục layout-land có nghĩa là bạn có hai bố cục riêng biệt sau đó bạn phải thực hiện setContentViewtrong onConfigurationChangedphương thức.

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

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        setContentView(R.layout.yourxmlinlayout-land);
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        setContentView(R.layout.yourxmlinlayoutfolder);
    }
}

Nếu bạn chỉ có một bố cục thì không cần thiết phải tạo setContentView trong phương thức này. đơn giản

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

19
Thay vì ghi đè, chỉ cần sử dụng layout / main.xml và layout-land / main.xml.
Jared Burrows


Tôi muốn phát hiện rằng hoạt động của tôi đã bị chấm dứt do xoay màn hình. Tôi đã triển khai onConfigurationChanged(Configuration newConfig)phương thức (như trong câu trả lời này), nhưng thay vì tự xử lý nó, tôi đặt cờ Boolean và sau đó gọi recreate()phương thức để Android tạo lại hoạt động theo cách bình thường của nó.
bàng hoàng

Một vấn đề với recreate()phương pháp này là nó khiến màn hình nhấp nháy màu đen trong thời gian ngắn. Vì lý do này, tôi đã sử dụng một cách tiếp cận khác: (1) lưu chiều rộng màn hình trong onCreate(...), (2) so sánh chiều rộng màn hình đã lưu với chiều rộng màn hình hiện tại trong bất kỳ phương pháp vòng đời nào khi hoạt động bị chấm dứt (ví dụ onSaveInstanceState(...):).
choáng váng

13

Chỉ muốn chỉ cho bạn một cách để lưu tất cả Gói của bạn sau onConfigurationChanged:

Tạo Gói mới ngay sau lớp của bạn:

public class MainActivity extends Activity {
    Bundle newBundy = new Bundle();

Tiếp theo, sau khi "void onCreate được bảo vệ" thêm vào:

@Override
public void onConfigurationChanged(Configuration newConfig) {
     super.onConfigurationChanged(newConfig);
     if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            onSaveInstanceState(newBundy);
        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
            onSaveInstanceState(newBundy);
        }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBundle("newBundy", newBundy);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    savedInstanceState.getBundle("newBundy");
}

Nếu bạn thêm điều này, tất cả các lớp đã nhồi nhét của bạn vào MainActivity sẽ được lưu.

Nhưng cách tốt nhất là thêm cái này vào AndroidManifest của bạn:

<activity name= ".MainActivity" android:configChanges="orientation|screenSize"/>

7
Điều này gây hiểu lầm. Việc triển khai onConfigurationChanged()làm cho nó để instanceState của bạn không bị phá hủy khi hướng thay đổi, vì vậy bạn không cần phải lưu nó. Bạn có thể muốn lưu nó cho các sự kiện khác trong vòng đời hoạt động, nhưng tôi không biết.
izzy

5

sử dụng phương pháp này

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
    {
        Toast.makeText(getActivity(),"PORTRAIT",Toast.LENGTH_LONG).show();
       //add your code what you want to do when screen on PORTRAIT MODE
    }
    else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
    {
        Toast.makeText(getActivity(),"LANDSCAPE",Toast.LENGTH_LONG).show();
        //add your code what you want to do when screen on LANDSCAPE MODE
   }
}

Và đừng quên Thêm cái này vào Androidmainfest.xml của bạn

android:configChanges="orientation|screenSize"

như thế này

<activity android:name=".MainActivity"
          android:theme="@style/Theme.AppCompat.NoActionBar"
          android:configChanges="orientation|screenSize">

    </activity>

2

Ghi đè phương thức của hoạt động onConfigurationChanged


Tôi muốn chỉ ra rằng nếu không có dòng sau bên trong thẻ <activity> trong tệp kê khai, thì lệnh gọi lại onConfigurationChanged () thậm chí sẽ không được kích hoạt. android: configChanges = "direction"
Sreekanth Karumanaghat 23/12/19

1

Tôi chỉ muốn đề xuất một giải pháp thay thế khác mà thực sự sẽ khiến một số bạn quan tâm, như đã giải thích ở trên:

android:configChanges="orientation|keyboardHidden" 

ngụ ý rằng chúng tôi khai báo rõ ràng bố cục sẽ được đưa vào.

Trong trường hợp chúng ta muốn giữ tự động tiêm nhờ vào các thư mục layout-land và layout. Tất cả những gì bạn phải làm là thêm nó vào onCreate:

    if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        getSupportActionBar().hide();

    } else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
        getSupportActionBar().show();
    }

Tại đây, chúng tôi hiển thị hoặc không hiển thị thanh tác vụ tùy thuộc vào hướng của điện thoại


0

Tạo một thể hiện của OrientationEventListenerlớp và kích hoạt nó.

OrientationEventListener mOrientationEventListener = new OrientationEventListener(YourActivity.this) {
    @Override
    public void onOrientationChanged(int orientation) {
        Log.d(TAG,"orientation = " + orientation);
    }
};

if (mOrientationEventListener.canDetectOrientation())
    mOrientationEventListener.enable();

2
Vui lòng không phá hoại câu trả lời của bạn. Nếu bạn muốn xóa nó, bạn có thể tìm thấy nút xóa ở dưới cùng bên trái của câu trả lời của bạn.
CalvT

0

Nếu câu trả lời được chấp nhận không phù hợp với bạn, hãy đảm bảo rằng bạn không xác định trong tệp kê khai:

android:screenOrientation="portrait"

Đó là trường hợp của tôi.


0

Trong trường hợp điều này được sử dụng cho một số nhà phát triển mới hơn vì nó không được chỉ định ở trên. Chỉ cần rất rõ ràng:

Bạn cần hai thứ nếu sử dụng onConfigurationChanged :

  1. Một onConfigurationChangedphương pháp trong Lớp hoạt động của bạn

  2. Chỉ định trong tệp kê khai của bạn những thay đổi cấu hình nào sẽ đượconConfigurationChanged phương pháp của bạn xử lý

Đoạn mã tệp kê khai trong các câu trả lời ở trên, mặc dù không nghi ngờ gì là chính xác đối với ứng dụng cụ thể chứa tệp kê khai, nhưng KHÔNG phải là chính xác những gì bạn cần thêm vào tệp kê khai của mình để kích hoạt phương thức onConfigurationChanged trong Lớp hoạt động của bạn. tức là mục nhập tệp kê khai dưới đây có thể không đúng với ứng dụng của bạn.

<activity name= ".MainActivity" android:configChanges="orientation|screenSize"/>

Trong mục nhập tệp kê khai ở trên, có nhiều hành động Android khác nhau android:configChanges=""có thể kích hoạt onCreate trong vòng đời Hoạt động của bạn.

Điều này rất quan trọng - Những cái KHÔNG được chỉ định trong tệp kê khai là những cái kích hoạt onCreate của bạnNhững cái được chỉ định trong tệp kê khai là những cái kích hoạt onConfigurationChangedphương thức của bạn trong Lớp hoạt động của bạn.

Vì vậy, bạn cần xác định những thay đổi cấu hình nào bạn cần để tự xử lý. Đối với Android Encyclopedally Challenged như tôi, tôi đã sử dụng cửa sổ bật ra gợi ý nhanh trong Android Studio và thêm vào hầu hết mọi tùy chọn cấu hình có thể. Liệt kê tất cả những thứ này về cơ bản nói rằng tôi sẽ xử lý mọi thứ và onCreate sẽ không bao giờ được gọi do cấu hình.

<activity name= ".MainActivity" android:configChanges="screenLayout|touchscreen|mnc|mcc|density|uiMode|fontScale|orientation|keyboard|layoutDirection|locale|navigation|smallestScreenSize|keyboardHidden|colorMode|screenSize"/>

Bây giờ rõ ràng là tôi không muốn xử lý mọi thứ, vì vậy tôi đã bắt đầu loại bỏ từng tùy chọn ở trên. Xây dựng lại và thử nghiệm ứng dụng của tôi sau mỗi lần xóa.

Một điểm quan trọng khác : Nếu chỉ có một tùy chọn cấu hình được xử lý tự động kích hoạt onCreate của bạn (Bạn không có nó được liệt kê trong tệp kê khai của mình ở trên), thì nó sẽ có vẻ như onConfigurationChangedkhông hoạt động. Bạn phải đưa tất cả những cái có liên quan vào tệp kê khai của mình.

Tôi đã kết thúc với 3 cái đang kích hoạt onCreate ban đầu, sau đó tôi đã thử nghiệm trên S10 + và tôi vẫn nhận được onCreate, vì vậy tôi phải thực hiện lại bài tập loại bỏ của mình và tôi cũng cần |screenSize. Vì vậy, hãy thử nghiệm trên một số nền tảng.

<activity name= ".MainActivity" android:configChanges="screenLayout|uiMode|orientation|screenSize"/>

Vì vậy, đề xuất của tôi, mặc dù tôi chắc rằng ai đó có thể chọc thủng lỗ hổng này:

  1. Thêm onConfigurationChangedphương thức của bạn vào Lớp hoạt động bằng TOAST hoặc LOG để bạn có thể biết khi nào nó hoạt động.

  2. Thêm tất cả các tùy chọn cấu hình có thể có vào tệp kê khai của bạn.

  3. Xác nhận onConfigurationChangedphương pháp của bạn đang hoạt động bằng cách thử nghiệm ứng dụng của bạn.

  4. Xóa từng tùy chọn cấu hình khỏi tệp kê khai của bạn tại một thời điểm, thử nghiệm ứng dụng của bạn sau mỗi tùy chọn.

  5. Thử nghiệm trên càng nhiều thiết bị càng tốt.

  6. Không sao chép / dán đoạn mã của tôi ở trên vào tệp kê khai của bạn. Các bản cập nhật Android thay đổi danh sách, vì vậy hãy sử dụng các gợi ý Android Studio pop-out để đảm bảo bạn nhận được tất cả.

Tôi hy vọng điều này giúp ai đó tiết kiệm thời gian.

onConfigurationChangedPhương pháp của tôi chỉ để biết thông tin bên dưới. onConfigurationChangedđược gọi trong vòng đời sau khi định hướng mới có sẵn, nhưng trước khi giao diện người dùng được tạo lại. Do đó, lần đầu tiên của tôi ifđể kiểm tra hướng hoạt động chính xác, và sau đó lần thứ hai được lồng ifvào nhau để xem khả năng hiển thị của UI ImageView của tôi cũng hoạt động chính xác.

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

        // Checks the orientation of the screen
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            pokerCardLarge = findViewById(R.id.pokerCardLgImageView);

            if(pokerCardLarge.getVisibility() == pokerCardLarge.VISIBLE){
                Bitmap image = ((BitmapDrawable)pokerCardLarge.getDrawable()).getBitmap();
                pokerCardLarge.setVisibility(pokerCardLarge.VISIBLE);
                pokerCardLarge.setImageBitmap(image);
            }

        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
            pokerCardLarge = findViewById(R.id.pokerCardLgImageView);

            if(pokerCardLarge.getVisibility() == pokerCardLarge.VISIBLE){
                Bitmap image = ((BitmapDrawable)pokerCardLarge.getDrawable()).getBitmap();
                pokerCardLarge.setVisibility(pokerCardLarge.VISIBLE);
                pokerCardLarge.setImageBitmap(image);
            }

        }
    }

0

để triển khai Kotilin ở dạng đơn giản nhất - chỉ kích hoạt khi màn hình thay đổi từ ngang <--> ngang nếu cần thiết bị phát hiện lật (180 độ), bạn sẽ cần phải chuyển sang các giá trị cảm biến trọng lực

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

val rotation = windowManager.defaultDisplay.rotation

    when (rotation) {            
        0 -> Log.d(TAG,"at zero degree")
        1 -> Log.d(TAG,"at 270 degree")
        2 -> Log.d(TAG,"at 180 degree")
        3 -> Log.d(TAG,"at 90 degree")


    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.