Android: อนุญาตภาพเหมือนและแนวนอนสำหรับแท็บเล็ต แต่บังคับให้ถ่ายภาพบุคคลในโทรศัพท์


191

ฉันต้องการให้แท็บเล็ตสามารถแสดงในแนวตั้งและแนวนอน (sw600dp หรือสูงกว่า) ได้ แต่โทรศัพท์จะถูก จำกัด เฉพาะแนวตั้งเท่านั้น ฉันไม่พบวิธีที่จะเลือกการวางแนวแบบมีเงื่อนไข ข้อเสนอแนะใด ๆ


วิธีหนึ่งที่จะไม่ออกแบบเลย์เอาต์แนวนอนสำหรับโทรศัพท์เช่นเดียวกับในโฟลเดอร์layout-landภายใน res
Ghost

12
นั่นจะทำให้เค้าโครงแนวตั้งแสดงในแนวนอนเท่านั้น มันจะไม่ป้องกันโทรศัพท์จากการหมุนเป็นแนวนอน
radley

คำตอบ:


446

นี่เป็นวิธีที่ดีในการใช้ทรัพยากรและบ่นขนาด

ใส่ทรัพยากร bool นี้ใน res / values ​​เป็น bools.xml หรืออะไรก็ตาม (ชื่อไฟล์ไม่สำคัญที่นี่):

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <bool name="portrait_only">true</bool>
    </resources>

ใส่อันนี้ใน res / values-sw600dp และ res / values-xlarge:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <bool name="portrait_only">false</bool>
    </resources>

ดูคำตอบเพิ่มเติมนี้สำหรับความช่วยเหลือในการเพิ่มไดเรกทอรีและไฟล์เหล่านี้ใน Android Studio

จากนั้นในวิธี onCreate ของกิจกรรมของคุณคุณสามารถทำได้:

    if(getResources().getBoolean(R.bool.portrait_only)){
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

อุปกรณ์ที่มีมากกว่า 600 DP ในทิศทางความกว้างที่มีขนาดเล็กหรือ X-ขนาดใหญ่บนก่อน Android 3.2 อุปกรณ์ (แท็บเล็ตโดยทั่วไป) จะทำตัวเหมือนปกติขึ้นอยู่กับการเซ็นเซอร์และการหมุนใช้ล็อค ฯลฯ ทุกอย่างอื่น (โทรศัพท์สวยมาก) จะเป็นแนวตั้งเท่านั้น


1
ฉันจำเป็นต้องใช้xlargeด้วยหรือsw600dpไม่ อาจไม่มีแท็บเล็ตใด ๆ ที่ทำงาน <3.2 วันนี้
theblang

7
สิ่งนี้อาจเริ่มกิจกรรมใหม่เมื่อเริ่มต้นในแนวนอนดูdeveloper.android.com/reference/android/app/…
Bondax

1
@Bondax ความคิดเห็นนั้นใช้เฉพาะ "หากกิจกรรมอยู่ในเบื้องหน้าหรือส่งผลกระทบต่อการวางแนวหน้าจอ" ซึ่งไม่สามารถเป็นได้เนื่องจากเราอยู่ใน onCreate ณ จุดนี้
Brian Christensen

1
@BrianChristensen onCreate()ผมสังเกตรีสตาร์ทกิจกรรมเมื่อตั้งค่าการวางแนวทางในการร้องขอ เมื่อฉันย้ายการโทรไปsetRequestedOrientation()ยังตำแหน่งอื่นในเวลาและบริบทการรีสตาร์ทจะไม่เกิดขึ้นอีก
Bondax

8
ถ้าฉันเริ่มต้นแอพในโหมดแนวนอนก็ยังคงแสดงโหมดแนวนอนชั่วครู่หนึ่ง
最白目

29

คุณสามารถลองด้วยวิธีนี้ก่อนรับขนาดหน้าจอของอุปกรณ์

if ((getResources().getConfiguration().screenLayout &      Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) {     
    Toast.makeText(this, "Large screen",Toast.LENGTH_LONG).show();

}
else if ((getResources().getConfiguration().screenLayout &      Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_NORMAL) {     
    Toast.makeText(this, "Normal sized screen" , Toast.LENGTH_LONG).show();

} 
else if ((getResources().getConfiguration().screenLayout &      Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_SMALL) {     
    Toast.makeText(this, "Small sized screen" , Toast.LENGTH_LONG).show();
}
else {
    Toast.makeText(this, "Screen size is neither large, normal or small" , Toast.LENGTH_LONG).show();
}

จากนั้นตั้งค่าการวางแนวตามที่

setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

4
ฉันควรใช้วิธีใดในเมธอด setRequestedOrientation () เมื่อ onCreate ได้เริ่มต้นมันได้เลือกแนวที่ต้องการแล้ว
Kenny Wyland

kenny ตรวจสอบสิ่งนี้ฉันคิดว่ามันอาจช่วยให้คุณstackoverflow.com/questions/2833474/…
Avi Kumar Manku

ฉันเห็นคำตอบนี้ถูกอัปเดตแล้ว แต่ฉันไม่แน่ใจว่าจะแก้ปัญหาได้หรือไม่ Configurationให้screenLayoutข้อมูล - DPI ในขณะที่คำถามเกี่ยวข้องกับขนาดหน้าจอของอุปกรณ์จริง - แท็บเล็ต VS โทรศัพท์ หมายความว่าคุณสามารถมีConfiguration.SCREENLAYOUT_SIZE_NORMALและมันจะเป็นแท็บเล็ต MDPI
nightfixed

ฉันเผชิญปัญหาstackoverflow.com/questions/42172864/…
Aditya Vyas-Lakhan

10

เสริมคำตอบที่ยอมรับ

คุณสามารถทำตามขั้นตอนต่อไปนี้ใน Android Studio เพื่อเพิ่มres/values-sw600dpและres/values-largeไดเรกทอรีด้วยbools.xmlไฟล์ของพวกเขา

ค่า-sw600dp

ก่อนอื่นจากแท็บโครงการเลือกตัวกรองโครงการ (แทน Android) ในเนวิเกเตอร์

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

จากนั้นคลิกขวาที่app/src/main/resไดเรกทอรี เลือกใหม่ > Android ไดเรกทอรีทรัพยากร

เลือกหน้าจอขนาดเล็กความกว้างและจากนั้นกด>>ปุ่ม

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

พิมพ์600ความกว้างของหน้าจอที่เล็กที่สุด ชื่อไดเรกทอรีจะถูกสร้างขึ้นโดยอัตโนมัติ ตอบตกลง.

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

จากนั้นคลิกขวาที่values-sw600dpไฟล์ที่สร้างขึ้นใหม่ เลือกใหม่ > แฟ้มทรัพยากรค่า พิมพ์boolsชื่อ

ค่าขนาดใหญ่

การเพิ่มvalues-largeไดเรกทอรีจำเป็นเฉพาะเมื่อคุณรองรับ Android 3.2 (API ระดับ 13) เท่านั้น มิฉะนั้นคุณสามารถข้ามขั้นตอนนี้ได้ สอดคล้องไดเรกทอรีไปvalues-large values-sw600dp( values-xlargeสอดคล้องกับvalues-sw720dp.)

หากต้องการสร้างvalues-largeไดเรกทอรีให้ทำตามขั้นตอนเดียวกับด้านบน แต่ในกรณีนี้ให้เลือกขนาดแทนที่จะเป็นความกว้างหน้าจอที่เล็กที่สุด เลือกขนาดใหญ่ ชื่อไดเรกทอรีจะถูกสร้างขึ้นโดยอัตโนมัติ

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

คลิกขวาที่ไดเรกทอรีก่อนสร้างbools.xmlไฟล์


2
แจ้งให้เราทราบหากวิธีนี้ใช้ไม่ได้และฉันจะแก้ไข มันใช้งานได้สำหรับฉัน ฉันได้หนึ่ง downvote แต่ไม่มีความคิดเห็นดังนั้นฉันไม่รู้ว่าจะแก้ไขอย่างไร
Suragch

9

นี่คือวิธีที่ฉันทำ (ได้รับแรงบันดาลใจจากhttp://androidblogger.blogspot.com/2011/08/orientation-for-both-phones-and-tablets.html ):

ใน AndroidManifest.xml สำหรับแต่ละกิจกรรมที่คุณต้องการสามารถเปลี่ยนระหว่างแนวตั้งและแนวนอน (ให้แน่ใจว่าคุณเพิ่ม screenSize - คุณไม่จำเป็นต้องใช้สิ่งนี้!) คุณไม่จำเป็นต้องตั้งแนวหน้าจอที่นี่ :

android:configChanges="keyboardHidden|orientation|screenSize"

วิธีการเพิ่มในแต่ละกิจกรรม:

public static boolean isXLargeScreen(Context context) {
    return (context.getResources().getConfiguration().screenLayout
    & Configuration.SCREENLAYOUT_SIZE_MASK)
    >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
} 

และ: (หากคุณไม่แทนที่วิธีนี้แอพจะโทร onCreate () เมื่อเปลี่ยนการวางแนว)

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

    if (!isXLargeScreen(getApplicationContext()) ) {            
        return; //keep in portrait mode if a phone      
    }

    //I set background images for landscape and portrait here
}

ใน onCreate () ของแต่ละกิจกรรม:

if (!isXLargeScreen(getApplicationContext())) { //set phones to portrait; 
   setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);            
}
else {
  //I set background images here depending on portrait or landscape orientation 
}

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


2
วางเลย์เอาต์แนวนอนลงในโฟลเดอร์เลย์เอาต์ของคุณ
radley

คุณจะได้รับข้อยกเว้นถ้าคุณไม่เรียก super onConfigurationChanged
RominaV

8

ต่อไปนี้คำตอบของจินนี่ผมคิดว่าวิธีที่เชื่อถือได้มากที่สุดที่จะทำมันจะเป็นดังนี้:

ตามที่อธิบายไว้ที่นี่ให้ใส่บูลีนในทรัพยากร sw600dp มันจะต้องมีคำนำหน้าswมิฉะนั้นมันจะไม่ทำงานอย่างถูกต้อง:

ใน res / values-sw600dp / dimens.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isTablet">true</bool>
</resources>

ใน res / values ​​/ dimens.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isTablet">false</bool>
</resources>

จากนั้นสร้างวิธีการดึงข้อมูลบูลีนนั้น:

public class ViewUtils {
    public static boolean isTablet(Context context){
        return context.getResources().getBoolean(R.bool.isTablet);
    }
}

และเป็นกิจกรรมพื้นฐานที่จะขยายจากกิจกรรมที่คุณต้องการพฤติกรรมนี้:

public abstract class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (!ViewUtils.isTablet(this)) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
    }
}

ดังนั้นแต่ละกิจกรรมจะขยาย BaseActivity:

public class LoginActivity extends BaseActivity //....

สำคัญ : แม้ว่าคุณจะขยายจากBaseActivityคุณต้องเพิ่มบรรทัดandroid:configChanges="orientation|screenSize"ในแต่ละบรรทัดActivityใน AndroidManifest.xml ของคุณ:

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

5

นี่มันช้าไปหน่อย แต่นี่คือXML-Onlyแต่โซลูชันแฮ็คที่ไม่ได้สร้างกิจกรรมใหม่setRequestedOrientationหากต้องเปลี่ยนการวางแนว:

https://stackoverflow.com/a/27015879/1281930


1
ใช้งานไม่ได้แท็บเล็ตมักใช้โทรศัพท์วางแนวเสมอ เห็นได้ชัดว่า Android: screenOrientation ถูกตั้งค่าอย่างแน่นอนหนึ่งครั้งสำหรับกิจกรรมทั้งหมดในรายการก่อนที่จะมีการปรับใช้ทรัพยากรใด ๆ
0101100101

2

ต่อไปนี้เป็นคำตอบที่ยอมรับได้ฉันกำลังเพิ่มไฟล์ kotlin ด้วยโซลูชันหวังว่าจะช่วยใครบางคน

วางทรัพยากรบูลนี้res/valuesเป็นbools.xmlหรืออะไรก็ตาม (ชื่อไฟล์ไม่สำคัญที่นี่):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="portrait_only">true</bool>
</resources>

ใส่สิ่งนี้ในres/values-sw600dpและres/values-sw600dp-land:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="portrait_only">false</bool>
</resources>

จากนั้นเพิ่มในบรรทัดด้านล่างในกิจกรรมหรือส่วนย่อยของคุณ

class MyActivity : Activity() {

    @SuppressLint("SourceLockedOrientationActivity")
    override fun onCreate(savedInstanceState: Bundle?) {
        if (resources.getBoolean(R.bool.portrait_only)) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        }
        super.onCreate(savedInstanceState)
    }

    @SuppressLint("SourceLockedOrientationActivity")
    override fun onConfigurationChanged(newConfig: Configuration) {
        if (resources.getBoolean(R.bool.portrait_only)) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        }
        super.onConfigurationChanged(newConfig)
    }
}

1

โซลูชันอื่น ๆ ใช้ไม่ได้สำหรับฉัน ฉันยังคงมีปัญหาการปฐมนิเทศแปลก ๆ กับบทสนทนาและปัญหาด้านสันทนาการ ทางออกของฉันคือการขยายกิจกรรมบังคับให้มันเป็นแนวตั้งในรายการ

ตัวอย่าง:

public class MainActivityPhone extends MainActivity {}

Manifest.xml:

        <activity
        android:screenOrientation="portrait"
        android:name=".MainActivityPhone"
        android:theme="@style/AppTheme.NoActionBar" />

ในกิจกรรม splashcreen:

    Intent i = null;
    boolean isTablet = getResources().getBoolean(R.bool.is_tablet);
    if (!isTablet)
        i = new Intent(this, MainActivityPhone.class);
    else
        i = new Intent(this, MainActivity.class);
    startActivity(i);

0

คำถามเก่าฉันรู้ เพื่อเรียกใช้แอพของคุณในโหมดแนวตั้งเสมอแม้ในขณะที่การวางแนวอาจจะเป็นหรือสลับ ฯลฯ (เช่นบนแท็บเล็ต) ฉันออกแบบฟังก์ชั่นนี้ที่ใช้ในการตั้งค่าอุปกรณ์ในแนวที่ถูกต้องโดยไม่จำเป็นต้องทราบว่า คุณสมบัติถูกจัดระเบียบบนอุปกรณ์

   private void initActivityScreenOrientPortrait()
    {
        // Avoid screen rotations (use the manifests android:screenOrientation setting)
        // Set this to nosensor or potrait

        // Set window fullscreen
        this.activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        DisplayMetrics metrics = new DisplayMetrics();
        this.activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

         // Test if it is VISUAL in portrait mode by simply checking it's size
        boolean bIsVisualPortrait = ( metrics.heightPixels >= metrics.widthPixels ); 

        if( !bIsVisualPortrait )
        { 
            // Swap the orientation to match the VISUAL portrait mode
            if( this.activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT )
             { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }
            else { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ); }
        }
        else { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); }

    }

ทำงานเหมือนจับใจ!

ข้อสังเกต: เปลี่ยนthis.activityตามกิจกรรมของคุณหรือเพิ่มไปยังกิจกรรมหลักและลบthis.activity;-)

หากคุณต้องการทำสิ่งที่ตรงกันข้ามคุณต้องเปลี่ยนรหัสเป็นแนวนอน (แต่ฉันคิดว่ามันชัดเจนในเรื่องนี้)


0

น่าเสียดายที่การใช้เมธอดsetRequestedOrientation (... )จะทำให้กิจกรรมรีสตาร์ทดังนั้นแม้ว่าคุณจะเรียกสิ่งนี้ในเมธอด onCreate มันจะผ่านวงจรชีวิตของกิจกรรมแล้วมันจะสร้างกิจกรรมเดียวกันในทิศทางที่ร้องขอ ดังนั้นที่คำตอบของ @Brian Christensen คุณควรพิจารณาว่ารหัสกิจกรรมอาจถูกเรียกสองครั้งซึ่งอาจมีผลเสีย (ไม่เพียง แต่มองเห็นได้เท่านั้น แต่ยังรวมถึงคำขอเครือข่ายการวิเคราะห์ ฯลฯ )

นอกจากนี้ในการตั้งค่าแอตทริบิวต์ configChanges ในไฟล์ Manifest ฉันคิดว่าเป็นการแลกเปลี่ยนที่ยิ่งใหญ่ซึ่งอาจต้องเสียค่าใช้จ่ายจำนวนมาก Android Devs ไม่แนะนำให้เปลี่ยนแอตทริบิวต์นั้น

ในที่สุดการพยายามตั้งค่าการแสดงผลหน้าจอแตกต่างกัน (เพื่อหลีกเลี่ยงปัญหาการเริ่มต้นใหม่) เป็นไปไม่ได้เป็นไปไม่ได้เนื่องจากมีรายการคงที่ซึ่งไม่สามารถเปลี่ยนแปลงได้

สรุป: ในความคิดของฉันคำแนะนำ @Brian Christensen เป็นการแลกเปลี่ยนที่ดีที่สุด แต่ต้องระวังปัญหาการรีสตาร์ทกิจกรรม

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