Tôi muốn máy tính bảng có thể hiển thị ở chế độ dọc và ngang (sw600dp trở lên), nhưng điện thoại chỉ bị giới hạn ở chế độ dọc. Tôi không thể tìm thấy bất kỳ cách nào để chọn một cách có điều kiện. Bất kỳ đề xuất?
Tôi muốn máy tính bảng có thể hiển thị ở chế độ dọc và ngang (sw600dp trở lên), nhưng điện thoại chỉ bị giới hạn ở chế độ dọc. Tôi không thể tìm thấy bất kỳ cách nào để chọn một cách có điều kiện. Bất kỳ đề xuất?
Câu trả lời:
Đây là một cách tốt để sử dụng tài nguyên và vòng loại kích thước .
Đặt tài nguyên bool này trong res / value dưới dạng bools.xml hoặc bất cứ điều gì (tên tệp không quan trọng ở đây):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="portrait_only">true</bool>
</resources>
Đặt cái này trong res / value-sw600dp và res / value-xlarge:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="portrait_only">false</bool>
</resources>
Xem câu trả lời bổ sung này để được trợ giúp thêm các thư mục và tệp này trong Android Studio.
Sau đó, trong phương thức onCreate của Hoạt động, bạn có thể thực hiện việc này:
if(getResources().getBoolean(R.bool.portrait_only)){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
Thiết bị hơn 600 dp theo hướng chiều rộng nhỏ nhất, hoặc x-lớn trên các thiết bị pre-Android 3.2 (viên nén, về cơ bản) sẽ cư xử như bình thường, dựa trên cảm biến và xoay người dùng khóa, vv . Mọi thứ khác (điện thoại, khá nhiều) sẽ chỉ là chân dung.
xlarge
quá hay tôi chỉ có thể sử dụng sw600dp
? Có lẽ không có máy tính bảng nào chạy <3,2 trong những ngày này.
onCreate()
. Khi tôi chuyển cuộc gọi đến setRequestedOrientation()
một vị trí khác theo thời gian và bối cảnh, việc khởi động lại đã không xảy ra nữa.
Trước tiên, bạn có thể thử cách này để có được kích thước màn hình của thiết bị
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();
}
và sau đó thiết lập định hướng theo đó
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Configuration
cung cấp screenLayout
thông tin - DPI. Trong khi câu hỏi liên quan đến kích thước màn hình thiết bị vật lý - điện thoại máy tính bảng VS. Có nghĩa là, bạn có thể có một Configuration.SCREENLAYOUT_SIZE_NORMAL
và nó sẽ là một máy tính bảng MDPI.
Bạn có thể thực hiện các bước sau trong Android Studio để thêm res/values-sw600dp
và res/values-large
thư mục với các bools.xml
tệp của họ .
Trước hết, từ tab Project, chọn bộ lọc Project (chứ không phải Android) trong bộ điều hướng.
Sau đó nhấp chuột phải vào app/src/main/res
thư mục. Chọn Mới > Thư mục tài nguyên Android .
Chọn Chiều rộng màn hình nhỏ nhất , rồi nhấn nút >> .
Nhập vào 600
cho chiều rộng màn hình nhỏ nhất. Tên thư mục sẽ được tạo tự động. Nói OK.
Sau đó nhấp chuột phải vào values-sw600dp
tập tin vừa tạo . Chọn Mới > Giá trị tệp tài nguyên . Nhập bools
tên.
Việc thêm một values-large
thư mục chỉ cần thiết nếu bạn đang hỗ trợ Android 3.2 (API cấp 13). Nếu không, bạn có thể bỏ qua bước này. Thư mục values-large
tương ứng với values-sw600dp
. ( values-xlarge
tương ứng với values-sw720dp
.)
Để tạo values-large
thư mục, hãy làm theo các bước tương tự như trên, nhưng trong trường hợp này, chọn Kích thước thay vì Chiều rộng màn hình nhỏ nhất. Chọn Lớn . Tên thư mục sẽ được tạo tự động.
Nhấp chuột phải vào thư mục như trước để tạo bools.xml
tập tin.
Đây là cách tôi đã làm (lấy cảm hứng từ http://androidblogger.blogspot.com/2011/08/orientation-for-both-phones-and-tablets.html ):
Trong AndroidManifest.xml, đối với từng hoạt động bạn muốn có thể thay đổi giữa dọc và ngang (đảm bảo bạn thêm screenSize - bạn không cần sử dụng điều này!) Bạn không cần đặt hướng màn hình ở đây. :
android:configChanges="keyboardHidden|orientation|screenSize"
Các phương thức để thêm vào trong mỗi Hoạt động:
public static boolean isXLargeScreen(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK)
>= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
và: (nếu bạn không ghi đè phương thức này, ứng dụng sẽ gọi onCreate () khi thay đổi hướng)
@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
}
Trong onCreate () của mỗi Hoạt động:
if (!isXLargeScreen(getApplicationContext())) { //set phones to portrait;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
else {
//I set background images here depending on portrait or landscape orientation
}
Điều duy nhất tôi dường như không thể tìm ra là làm thế nào để ứng dụng thay đổi các tệp bố cục khi chuyển từ ngang sang dọc hoặc ngược lại. Tôi giả sử câu trả lời đang làm một cái gì đó tương tự như những gì liên kết ở trên làm, nhưng tôi không thể làm cho nó hoạt động với tôi - nó đã xóa tất cả dữ liệu của tôi. Nhưng nếu bạn có một ứng dụng đủ đơn giản mà bạn có cùng tệp bố cục cho dọc và ngang, thì ứng dụng này sẽ hoạt động.
Theo câu trả lời của Ginny , tôi nghĩ cách đáng tin cậy nhất để làm điều đó là như sau:
Như được mô tả ở đây , đặt một boolean trong tài nguyên sw600dp. Nó phải có tiền tố sw nếu không nó sẽ không hoạt động đúng:
trong res / value-sw600dp / dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isTablet">true</bool>
</resources>
trong res / value / dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isTablet">false</bool>
</resources>
Sau đó thực hiện một phương thức để lấy boolean đó:
public class ViewUtils {
public static boolean isTablet(Context context){
return context.getResources().getBoolean(R.bool.isTablet);
}
}
Và một hoạt động cơ bản để mở rộng từ các hoạt động mà bạn muốn hành vi này:
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!ViewUtils.isTablet(this)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
}
Vì vậy, mỗi hoạt động sẽ mở rộng BaseActivity:
public class LoginActivity extends BaseActivity //....
Quan trọng : ngay cả khi bạn mở rộng từ BaseActivity
, bạn phải thêm dòng android:configChanges="orientation|screenSize"
vào từng dòng Activity
trong AndroidManifest.xml:
<activity
android:name=".login.LoginActivity"
android:configChanges="orientation|screenSize">
</activity>
Chà, điều này hơi muộn nhưng, đây là một giải pháp chỉ dành cho XML nhưng là một giải pháp hack không tái tạo một hoạt động như setRequestedOrientation
nếu phải thay đổi hướng:
Theo câu trả lời được chấp nhận , tôi đang thêm tệp kotlin với giải pháp hy vọng nó sẽ giúp được ai đó
Đặt tài nguyên bool này vào res/values
dưới dạng bools.xml hoặc bất cứ điều gì (tên tệp không quan trọng ở đây):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="portrait_only">true</bool>
</resources>
Đặt cái này vào res/values-sw600dp
và res/values-sw600dp-land
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="portrait_only">false</bool>
</resources>
Sau đó, thêm nó vào các dòng dưới đây trong hoạt động hoặc phân mảnh của bạn
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)
}
}
Các giải pháp khác không hiệu quả với tôi. Tôi vẫn có một số vấn đề định hướng kỳ lạ với các hộp thoại và các vấn đề giải trí. Giải pháp của tôi là mở rộng Hoạt động, buộc nó là chân dung trong bảng kê khai.
Thí dụ:
public class MainActivityPhone extends MainActivity {}
tệp kê khai:
<activity
android:screenOrientation="portrait"
android:name=".MainActivityPhone"
android:theme="@style/AppTheme.NoActionBar" />
trong hoạt động màn hình:
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);
Câu hỏi cũ tôi biết. Để chạy ứng dụng của bạn luôn ở chế độ dọc ngay cả khi định hướng có thể bị hoán đổi, v.v. các tính năng được tổ chức trên thiết bị.
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); }
}
Hoạt động như một lá bùa!
THÔNG BÁO: Thay đổi this.activity
theo hoạt động của bạn hoặc thêm nó vào hoạt động chính và xóa this.activity
;-)
Nếu bạn muốn làm ngược lại, bạn phải thay đổi mã thành ngang (nhưng tôi nghĩ rõ ràng làm thế nào để làm điều này).
Thật không may, sử dụng phương thức setRequestedOrientation (...) sẽ khiến hoạt động khởi động lại, vì vậy ngay cả khi bạn gọi phương thức này trong phương thức onCreate, nó sẽ đi qua vòng đời hoạt động và sau đó nó sẽ tạo lại hoạt động tương tự theo hướng được yêu cầu. Vì vậy, tại câu trả lời của @Brian Christensen, bạn nên xem xét rằng mã hoạt động có thể được gọi hai lần, điều này có thể có tác động xấu (không chỉ trực quan, mà còn ở các yêu cầu mạng, phân tích, v.v.).
Hơn nữa, để đặt thuộc tính configChanges trong tệp kê khai theo ý kiến của tôi là một sự đánh đổi lớn, có thể mất chi phí tái cấu trúc lớn. Android Devs không khuyến nghị thay đổi thuộc tính đó .
Cuối cùng, cố gắng thiết lập màn hình khác nhau bằng cách nào đó (để tránh sự cố khởi động lại) là không thể, không thể tĩnh do biểu hiện tĩnh không thể thay đổi, theo lập trình, chỉ có thể gọi phương thức đó trong hoạt động đã bắt đầu.
Tóm tắt: Theo tôi, đề xuất @Brian Christensen là sự đánh đổi tốt nhất, nhưng lưu ý về vấn đề hoạt động khởi động lại.
layout-land
bên trongres
.