ฉันต้องการให้แท็บเล็ตสามารถแสดงในแนวตั้งและแนวนอน (sw600dp หรือสูงกว่า) ได้ แต่โทรศัพท์จะถูก จำกัด เฉพาะแนวตั้งเท่านั้น ฉันไม่พบวิธีที่จะเลือกการวางแนวแบบมีเงื่อนไข ข้อเสนอแนะใด ๆ
ฉันต้องการให้แท็บเล็ตสามารถแสดงในแนวตั้งและแนวนอน (sw600dp หรือสูงกว่า) ได้ แต่โทรศัพท์จะถูก จำกัด เฉพาะแนวตั้งเท่านั้น ฉันไม่พบวิธีที่จะเลือกการวางแนวแบบมีเงื่อนไข ข้อเสนอแนะใด ๆ
คำตอบ:
นี่เป็นวิธีที่ดีในการใช้ทรัพยากรและบ่นขนาด
ใส่ทรัพยากร 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 อุปกรณ์ (แท็บเล็ตโดยทั่วไป) จะทำตัวเหมือนปกติขึ้นอยู่กับการเซ็นเซอร์และการหมุนใช้ล็อค ฯลฯ ทุกอย่างอื่น (โทรศัพท์สวยมาก) จะเป็นแนวตั้งเท่านั้น
xlarge
ด้วยหรือsw600dp
ไม่ อาจไม่มีแท็บเล็ตใด ๆ ที่ทำงาน <3.2 วันนี้
onCreate()
ผมสังเกตรีสตาร์ทกิจกรรมเมื่อตั้งค่าการวางแนวทางในการร้องขอ เมื่อฉันย้ายการโทรไปsetRequestedOrientation()
ยังตำแหน่งอื่นในเวลาและบริบทการรีสตาร์ทจะไม่เกิดขึ้นอีก
คุณสามารถลองด้วยวิธีนี้ก่อนรับขนาดหน้าจอของอุปกรณ์
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);
Configuration
ให้screenLayout
ข้อมูล - DPI ในขณะที่คำถามเกี่ยวข้องกับขนาดหน้าจอของอุปกรณ์จริง - แท็บเล็ต VS โทรศัพท์ หมายความว่าคุณสามารถมีConfiguration.SCREENLAYOUT_SIZE_NORMAL
และมันจะเป็นแท็บเล็ต MDPI
คุณสามารถทำตามขั้นตอนต่อไปนี้ใน Android Studio เพื่อเพิ่มres/values-sw600dp
และres/values-large
ไดเรกทอรีด้วยbools.xml
ไฟล์ของพวกเขา
ก่อนอื่นจากแท็บโครงการเลือกตัวกรองโครงการ (แทน 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
ไฟล์
นี่คือวิธีที่ฉันทำ (ได้รับแรงบันดาลใจจาก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
}
สิ่งเดียวที่ฉันคิดไม่ออกก็คือวิธีทำให้แอพเปลี่ยนไฟล์เลย์เอาต์เมื่อสลับจากแนวนอนเป็นแนวตั้งหรือในทางกลับกัน ฉันคิดว่าคำตอบคือทำสิ่งที่คล้ายกับสิ่งที่ลิงก์ด้านบนทำ แต่ฉันไม่สามารถใช้งานได้สำหรับฉัน - มันลบข้อมูลทั้งหมดของฉัน แต่ถ้าคุณมีแอพที่ง่ายพอที่คุณมีไฟล์เลย์เอาต์เดียวกันสำหรับแนวตั้งและแนวนอนสิ่งนี้น่าจะใช้ได้
ต่อไปนี้คำตอบของจินนี่ผมคิดว่าวิธีที่เชื่อถือได้มากที่สุดที่จะทำมันจะเป็นดังนี้:
ตามที่อธิบายไว้ที่นี่ให้ใส่บูลีนในทรัพยากร 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>
นี่มันช้าไปหน่อย แต่นี่คือXML-Onlyแต่โซลูชันแฮ็คที่ไม่ได้สร้างกิจกรรมใหม่setRequestedOrientation
หากต้องเปลี่ยนการวางแนว:
ต่อไปนี้เป็นคำตอบที่ยอมรับได้ฉันกำลังเพิ่มไฟล์ 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)
}
}
โซลูชันอื่น ๆ ใช้ไม่ได้สำหรับฉัน ฉันยังคงมีปัญหาการปฐมนิเทศแปลก ๆ กับบทสนทนาและปัญหาด้านสันทนาการ ทางออกของฉันคือการขยายกิจกรรมบังคับให้มันเป็นแนวตั้งในรายการ
ตัวอย่าง:
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);
คำถามเก่าฉันรู้ เพื่อเรียกใช้แอพของคุณในโหมดแนวตั้งเสมอแม้ในขณะที่การวางแนวอาจจะเป็นหรือสลับ ฯลฯ (เช่นบนแท็บเล็ต) ฉันออกแบบฟังก์ชั่นนี้ที่ใช้ในการตั้งค่าอุปกรณ์ในแนวที่ถูกต้องโดยไม่จำเป็นต้องทราบว่า คุณสมบัติถูกจัดระเบียบบนอุปกรณ์
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
;-)
หากคุณต้องการทำสิ่งที่ตรงกันข้ามคุณต้องเปลี่ยนรหัสเป็นแนวนอน (แต่ฉันคิดว่ามันชัดเจนในเรื่องนี้)
น่าเสียดายที่การใช้เมธอดsetRequestedOrientation (... )จะทำให้กิจกรรมรีสตาร์ทดังนั้นแม้ว่าคุณจะเรียกสิ่งนี้ในเมธอด onCreate มันจะผ่านวงจรชีวิตของกิจกรรมแล้วมันจะสร้างกิจกรรมเดียวกันในทิศทางที่ร้องขอ ดังนั้นที่คำตอบของ @Brian Christensen คุณควรพิจารณาว่ารหัสกิจกรรมอาจถูกเรียกสองครั้งซึ่งอาจมีผลเสีย (ไม่เพียง แต่มองเห็นได้เท่านั้น แต่ยังรวมถึงคำขอเครือข่ายการวิเคราะห์ ฯลฯ )
นอกจากนี้ในการตั้งค่าแอตทริบิวต์ configChanges ในไฟล์ Manifest ฉันคิดว่าเป็นการแลกเปลี่ยนที่ยิ่งใหญ่ซึ่งอาจต้องเสียค่าใช้จ่ายจำนวนมาก Android Devs ไม่แนะนำให้เปลี่ยนแอตทริบิวต์นั้น
ในที่สุดการพยายามตั้งค่าการแสดงผลหน้าจอแตกต่างกัน (เพื่อหลีกเลี่ยงปัญหาการเริ่มต้นใหม่) เป็นไปไม่ได้เป็นไปไม่ได้เนื่องจากมีรายการคงที่ซึ่งไม่สามารถเปลี่ยนแปลงได้
สรุป: ในความคิดของฉันคำแนะนำ @Brian Christensen เป็นการแลกเปลี่ยนที่ดีที่สุด แต่ต้องระวังปัญหาการรีสตาร์ทกิจกรรม
layout-land
ภายในres