Flutter: จะป้องกันการเปลี่ยนแนวอุปกรณ์และบังคับแนวตั้งได้อย่างไร?


152

ฉันต้องการป้องกันไม่ให้แอปพลิเคชันของฉันเปลี่ยนการวางแนวและบังคับให้เค้าโครงติดกับ "แนวตั้ง"

ใน main.dart ฉันใส่:

void main(){
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown
  ]);
  runApp(new MyApp());
}

แต่เมื่อฉันใช้ปุ่มหมุนของ Android Simulator เค้าโครง "ตาม" การวางแนวอุปกรณ์ใหม่ ...

ฉันจะแก้ปัญหานี้ได้อย่างไร

ขอบคุณ


4
สมมติว่าคุณนำเข้า'package:flutter/services.dart'แล้วอาจเป็นข้อผิดพลาด: github.com/flutter/flutter/issues/13238
Brian Kung

ไม่แน่ใจว่าเหตุใดจึงเกิดขึ้นกับคุณ ฉันลองรันโค้ดของคุณบนอีมูเลเตอร์และอุปกรณ์ของฉันเองและมันก็ใช้งานได้ดี
Hemanth Raj

SystemChrome.setPreferredOrientationsส่งคืนแบบอะซิงโครนัสดังนั้นดูเหมือนว่าrunAppควรอยู่ในไฟล์then.
Ken

คำตอบ:


222

นำเข้าpackage:flutter/services.dartแล้ว

ใส่SystemChrome.setPreferredOrientationsภายในWidget build()วิธี

ตัวอย่าง:

  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.portraitUp,
        DeviceOrientation.portraitDown,
      ]);
      return new MaterialApp(...);
    }
  }

อัปเดต

โซลูชันนี้อาจใช้ไม่ได้กับอุปกรณ์ IOS บางรุ่นตามที่ระบุไว้ในเอกสาร Flutter ที่อัปเดตเมื่อ ต.ค. 2019

พวกเขาแนะนำให้แก้ไขการวางแนวโดยตั้งค่า UISupportedInterfaceOrientations ใน Info.plist เช่นนี้

<array>
    <string>UIInterfaceOrientationPortrait</string>
</array>

สำหรับข้อมูลเพิ่มเติมhttps://github.com/flutter/flutter/issues/27235#issuecomment-508995063


3
หากคุณใส่ SystemChrome.setPreferredOrientations เป็นหลักคุณจะได้รับข้อผิดพลาด: ServicesBinding.defaultBinaryMessenger ถูกเข้าถึงก่อนที่การเชื่อมโยงจะเริ่มต้น การแทรกโค้ดในบิลด์ทำงานได้เนื่องจากการเชื่อมโยงได้รับการเตรียมใช้งานแล้ว ณ จุดนี้
Golden Lion

83

@boeledi หากคุณต้องการ "ล็อก" การวางแนวอุปกรณ์และไม่อนุญาตให้เปลี่ยนเมื่อผู้ใช้หมุนโทรศัพท์คุณสามารถตั้งค่าได้ง่ายๆดังนี้

// This did not work as requirement
void main() {
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
  runApp(new MyApp());
}

คุณต้องรอจนกว่าsetPreferredOrientationsจะเสร็จสิ้นจากนั้นจึงเริ่มแอพ

// This will works always for lock screen Orientation.
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
    .then((_) {
      runApp(new MyApp());
    });
}

1
บางครั้งอาจเกิดข้อผิดพลาดขณะรวบรวมคุณควรใช้โซลูชันดั้งเดิม การเพิ่ม 'android: screenOrientation = "portrait"' ไปยัง MainActivity บน AndroidManifest ตามที่ Abeer Iqbal แนะนำนั้นใช้ได้ผลกับฉันบน Android
Tincho825

53

iOS:

การโทรใช้SystemChrome.setPreferredOrientations()ไม่ได้สำหรับฉันและฉันต้องเปลี่ยนDevice Orientationในโครงการ Xcodeดังต่อไปนี้:

ป้อนคำอธิบายภาพที่นี่

Android:

ตั้งค่าscreenOrientationแอตทริบิวต์เป็นportraitสำหรับกิจกรรมหลักในไฟล์android/app/src/main/AndroidManifest.xmlดังต่อไปนี้:

ป้อนคำอธิบายภาพที่นี่


ฉันมีปัญหาเดียวกันคุณเปิดใช้งานบน iPad หรือไม่? ฉันทดสอบบน iPad เท่านั้นและดูเหมือนว่าจะเป็นปัญหา: github.com/flutter/flutter/issues/27235
Boy

android: แอตทริบิวต์นี้ถูกเพิ่มใน API ระดับ 24
BloodLoss

ฉันใช้screenOrientationตั้งแต่ API ระดับ 8 สำหรับ Android @BloodLoss ฉันคิดว่าคุณอ่านในเอกสาร แต่เกี่ยวกับresizeableActivityแอตทริบิวต์ ตรวจสอบลิงค์อีกครั้ง ^^
Erick M. Sprengel

23

เมธอด 'setPreferredOrientations' ส่งคืนวัตถุในอนาคต ตามเอกสารประกอบอนาคตแสดงถึงคุณค่าบางอย่างที่จะมีให้ในอนาคต นั่นเป็นเหตุผลที่คุณต้องรอจนกว่าจะพร้อมใช้งานแล้วจึงดำเนินการต่อด้วยแอปพลิเคชัน ดังนั้นจะมีการใช้เมธอด 'แล้ว' ซึ่งตามคำจำกัดความ "ลงทะเบียนการเรียกกลับที่จะเรียกเมื่ออนาคตเสร็จสมบูรณ์" ดังนั้นคุณจะต้องใช้รหัสนี้:

  void main() {
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) {
      runApp(new App());
    });
   }

นอกจากนี้ต้องนำเข้าไฟล์ต่อไปนี้:

'package: flutter / services.dart'


ฉันสามารถยืนยันได้ว่ามันได้ผล แต่ใช้ whenComplete () แทน then () เมื่อฟังก์ชันไม่มีพารามิเตอร์
Csaba Gergely

22

เปิด android / app / src / main / AndroidManifest.xml และเพิ่มบรรทัดต่อไปนี้ใน MainActivity:

android:screenOrientation="portrait"

หากคุณมีสิ่งนี้:

<activity
        android:name=".MainActivity"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme"
        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
        android:hardwareAccelerated="true"
        android:windowSoftInputMode="adjustResize">

คุณควรลงเอยด้วยสิ่งนี้:

<activity
        android:name=".MainActivity"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme"
        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
        android:hardwareAccelerated="true"
        android:screenOrientation="portrait"
        android:windowSoftInputMode="adjustResize">

สิ่งนี้ใช้ได้กับ Android ใน iOS คุณจะต้องเปลี่ยนสิ่งนี้จากหน้า Xcode: https://i.stack.imgur.com/hswoe.png (ตามที่ Hejazi กล่าว)


ขอบคุณโปรดจำไว้ว่าลำดับของ "แนวตั้ง" หลังจาก configChanges "orientation" มีความหมาย
MR_AMDEV

14

ใส่ WidgetsFlutterBinding.ensureInitialized () มิฉะนั้นคุณจะได้รับข้อผิดพลาดขณะสร้าง

import 'package:flutter/services.dart';

    void main() async => {
          WidgetsFlutterBinding.ensureInitialized(),

          await SystemChrome.setPreferredOrientations(
              [DeviceOrientation.portraitUp]), // To turn off landscape mode

          runApp(MainApp())
        };

13

ก่อนอื่นให้นำเข้าสิ่งนี้ในไฟล์main.dart

import 'package:flutter/services.dart';

จากนั้นอย่าคัดลอกวางแต่ให้ดู (จำ) และเขียนโค้ดด้านล่างในmain.dartไฟล์

วิธีบังคับในโหมดแนวตั้ง :

void main() {
  SystemChrome.setPreferredOrientations(
      [DeviceOrientation.portraitUp,DeviceOrientation.portraitDown])
      .then((_) => runApp(MyApp()),
  );

วิธีบังคับในโหมดแนวนอน :

   void main() {
      SystemChrome.setPreferredOrientations(
          [DeviceOrientation.landscapeLeft,DeviceOrientation.landscapeRight])
          .then((_) => runApp(MyApp()),
      );

1
ขอบคุณที่เตือนผู้คนไม่ให้คัดลอกวางสุ่มสี่สุ่มห้า
Ryan

1
ฉันเห็นว่าทำไมคุณขอไม่คัดลอกวาง ... ตอนจบ} หายไป ... ฉันคัดลอกวาง ... :)
rohan koshti

5

setPreferredOrientationส่งคืน a Future<void>ดังนั้นจึงเป็นแบบอะซิงโครนัส แนวทางที่อ่านง่ายที่สุดคือการกำหนดmainแบบอะซิงโครนัส:

Future<void> main() async {
  await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
  return runApp(new MyApp());
}

3
ฉันไม่เห็นด้วยอย่างยิ่ง awaitเป็นรูปแบบการเขียนโปรแกรมที่แพร่หลายซึ่งมีอยู่ในหลายภาษาและมีความชัดเจนมากว่าอะไร thenสร้างระดับของการทำรัง หากคุณมีความต่อเนื่องสามหรือสี่รายการthenเริ่มที่จะอ่านยากมากอย่างแน่นอน
Rob Lyndon

.thenสามารถล่ามโซ่แทนการทำรังได้ตามที่คาดFutureOrไว้ก. สิ่งนี้ช่วยให้ฉันใช้แนวทางการทำงานได้มากขึ้นซึ่งอ่านง่ายและสวยงาม ตัวอย่างเช่นฉันสามารถใช้เนื้อความแทนการใช้ตัวยึดได้โดยการผูก "แล้ว"
Mateus Felipe

บางครั้งอาจเกิดข้อผิดพลาดขณะรวบรวมคุณควรใช้โซลูชันดั้งเดิม การเพิ่ม 'android: screenOrientation = "portrait"' ไปยัง MainActivity บน AndroidManifest ตามที่ Abeer Iqbal แนะนำนั้นใช้ได้ผลกับฉันบน Android
Tincho825

หากคุณพบข้อผิดพลาด: "Unhandled Exception: ServicesBinding.defaultBinaryMessenger ถูกเข้าถึงก่อนที่การเชื่อมโยงจะเริ่มต้น" ลองใช้การแก้ไขนี้: stackoverflow.com/questions/57689492/…
Fillipe Silva

4

เพียงเพิ่มโค้ดบรรทัดต่อไปนี้ในไฟล์ main.dart

SystemChrome.setPreferredOrientations([
  DeviceOrientation.portraitUp,
]);

และอย่าลืมนำเข้าไฟล์ services.dart ตัวอย่างได้รับด้านล่าง!

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
    runApp(MyApp());
}


class MyApp extends StatelessWidget {
     @override
     Widget build(BuildContext context) {

      SystemChrome.setPreferredOrientations([
        DeviceOrientation.portraitUp,
      ]);

      return MaterialApp(
        home: Scaffold(
          body: Center(child: Text("A Flutter Example!")),
     ),
   );
  }
}

3

ด้านล่างนี้คือตัวอย่างอย่างเป็นทางการของทีม Flutter https://github.com/flutter/samples/blob/master/veggieseasons/lib/main.dart

import 'package:flutter/services.dart' show DeviceOrientation, SystemChrome;

void main() {
    WidgetsFlutterBinding.ensureInitialized();
    SystemChrome.setPreferredOrientations([
        DeviceOrientation.portraitUp,
        DeviceOrientation.portraitDown,
    ]);
    runApp(HomeScreen());
}

1

สำหรับเวอร์ชันใหม่ของการกระพือปีกพร้อมกับการตั้งค่าpreferred Orientationเราจำเป็นต้องเพิ่มบรรทัดพิเศษหนึ่งบรรทัดเช่น

 WidgetsFlutterBinding.ensureInitialized();

รหัสการทำงานสำหรับสิ่งนี้คือ -

import 'package:flutter/services.dart';
    void main() {
          WidgetsFlutterBinding.ensureInitialized();
          SystemChrome.setPreferredOrientations([
            DeviceOrientation.portraitUp,
            DeviceOrientation.portraitDown
          ]);
          runApp(MyApp());
        }

1

นำเข้า 'package: flutter / services.dart';

จากนั้นคุณรวมบรรทัดของโค้ดด้านล่างในไฟล์ main.dart ของคุณและในวิธีการหลักของคุณดังนี้:

WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitDown,
    DeviceOrientation.portraitUp,
  ]);

runApp(myApp());


1

สำหรับคนที่พวกเขากำลังอ่านคำถามนี้ในขณะนี้ วิธีที่ง่ายที่สุดที่ฉันพบและใช้ได้กับทั้งอุปกรณ์ Android และ ios

 void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations(
    [
      DeviceOrientation.portraitUp,
      DeviceOrientation.portraitDown,
    ],
  ).then((val) {
    runApp(YourAppName());
  });
}

0

ลอง

 void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await SystemChrome.setPreferredOrientations(
          [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); 
    
      runApp(MyApp());
 }

คุณยังสามารถเปลี่ยนการตั้งค่าการวางแนวหน้าจอในไฟล์ manifest ของ android และ ios info.plist


0

หากคุณกำลังแก้ไขสิ่งนี้จากอินเทอร์เฟซ xcode จะไม่มีการเปลี่ยนแปลงสำหรับ ipad สำหรับส่วนของ ipad คุณต้องแก้ไขไฟล์ info.plist จาก android studio คุณจะเห็นในรายการอาร์เรย์เช่น "~ ipad" มีสองส่วนใน info.plist คุณต้องแก้ไขด้วยตนเองสำหรับทั้ง iphone และ ipad


0

โซลูชันนี้ได้ผลสำหรับฉันในสองโครงการที่แตกต่างกันสำหรับ Android ไม่สามารถรับประกันได้ว่าจะใช้งานได้กับ iOS ด้วย ฉันได้อ่านคำตอบก่อนหน้านี้ทั้งหมดแล้วและฉันคิดว่าทางออกที่ดีที่สุดและง่ายที่สุดคือทำดังนี้:

Android:

ด้วยวิธีนี้คุณจะหลีกเลี่ยง "รอ" "async" และ "จากนั้น" ทั้งหมดที่อาจยุ่งเกี่ยวกับรหัสของคุณ

/// this is in main.dart

main(){
  WidgetsFlutterBinding.ensureInitialized();

  runApp(
    MaterialApp(
      initialRoute: '/root',
      routes: {
        '/root': (context) => MyApp(),
      },
      title: "Your App Title",
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    /// ENFORCE DEVICE ORIENTATION PORTRAIT ONLY
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.portraitUp,
      DeviceOrientation.portraitDown
    ]);

    /// RUN THE APP
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

iOS:

ฉันคิดว่าการอัปเดตคำตอบนี้เป็นทางออกที่ดีที่สุดสำหรับ iOS

!! การปฏิเสธความรับผิด !! ฉันได้ทำการวิจัยเล็กน้อยและเห็นได้ชัดว่าเอกสารที่นี่ระบุว่า:

setPreferredOrientations method Limitations:

"This setting will only be respected on iPad if multitasking is disabled."

นี่คือวิธีปิดใช้งานมัลติทาสก์ (AKA เปิดตัวเลือก "ต้องใช้เต็มหน้าจอ") จาก XCode

การแก้ไขที่เป็นไปได้อื่นสำหรับ iOS

คุณอาจลองใช้อันนี้ก็ได้ ฉันยังไม่ได้ลองใช้เป็นการส่วนตัวเนื่องจากฉันไม่มี iPad หรือ XCode บนพีซีของฉัน แต่มันก็คุ้มค่าที่จะยิง


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.