نمایشگرهای تاشو بزرگ و حالتهای تا شده منحصر به فرد، تجربه کاربری جدیدی را در دستگاههای تاشو امکانپذیر میسازد. برای آگاه کردن برنامه خود، از کتابخانه Jetpack WindowManager استفاده کنید، که یک سطح API برای ویژگیهای پنجره دستگاه تاشو مانند تا و لولا فراهم میکند. وقتی برنامه شما از تا کردن آگاه باشد، میتواند طرحبندی خود را برای جلوگیری از قرار دادن محتوای مهم در ناحیه چینها یا لولاها تنظیم کند و از چینها و لولاها به عنوان جداکننده طبیعی استفاده کند.
درک اینکه آیا یک دستگاه از پیکربندیهایی مانند وضعیت قرارگیری روی میز یا کتاب پشتیبانی میکند یا خیر، میتواند تصمیمات مربوط به پشتیبانی از طرحبندیهای مختلف یا ارائه ویژگیهای خاص را راهنمایی کند.
اطلاعات پنجره
رابط WindowInfoTracker
در Jetpack WindowManager اطلاعات طرح بندی پنجره را در معرض دید قرار می دهد. متد windowLayoutInfo()
واسط جریانی از دادههای WindowLayoutInfo
را برمیگرداند که برنامه شما را در مورد وضعیت فولد دستگاه تاشو مطلع میکند. متد WindowInfoTracker#getOrCreate()
نمونه ای از WindowInfoTracker
ایجاد می کند.
WindowManager برای جمع آوری داده های WindowLayoutInfo
با استفاده از جریان های Kotlin و callbacks جاوا پشتیبانی می کند.
کاتلین جریان دارد
برای شروع و توقف جمعآوری دادههای WindowLayoutInfo
، میتوانید از یک برنامهریزی با قابلیت راهاندازی مجدد استفاده کنید که در آن بلوک کد repeatOnLifecycle
زمانی اجرا میشود که چرخه حیات حداقل STARTED
است و با STOPPED
چرخه حیات متوقف میشود. اجرای بلوک کد به طور خودکار با شروع مجدد چرخه حیات مجدداً STARTED
می شود. در مثال زیر، بلوک کد داده های WindowLayoutInfo
را جمع آوری و استفاده می کند:
class DisplayFeaturesActivity : AppCompatActivity() {
private lateinit var binding: ActivityDisplayFeaturesBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDisplayFeaturesBinding.inflate(layoutInflater)
setContentView(binding.root)
lifecycleScope.launch(Dispatchers.Main) {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
WindowInfoTracker.getOrCreate(this@DisplayFeaturesActivity)
.windowLayoutInfo(this@DisplayFeaturesActivity)
.collect { newLayoutInfo ->
// Use newLayoutInfo to update the layout.
}
}
}
}
}
تماس های جاوا
لایه سازگاری پاسخ به تماس موجود در وابستگی androidx.window:window-java
به شما امکان میدهد بهروزرسانیهای WindowLayoutInfo
را بدون استفاده از جریان Kotlin جمعآوری کنید. این آرتیفکت شامل کلاس WindowInfoTrackerCallbackAdapter
است که یک WindowInfoTracker
برای پشتیبانی از ثبت (و لغو ثبت) تماسها برای دریافت بهروزرسانیهای WindowLayoutInfo
تطبیق میدهد، به عنوان مثال:
public class SplitLayoutActivity extends AppCompatActivity {
private WindowInfoTrackerCallbackAdapter windowInfoTracker;
private ActivitySplitLayoutBinding binding;
private final LayoutStateChangeCallback layoutStateChangeCallback =
new LayoutStateChangeCallback();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivitySplitLayoutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
windowInfoTracker =
new WindowInfoTrackerCallbackAdapter(WindowInfoTracker.getOrCreate(this));
}
@Override
protected void onStart() {
super.onStart();
windowInfoTracker.addWindowLayoutInfoListener(
this, Runnable::run, layoutStateChangeCallback);
}
@Override
protected void onStop() {
super.onStop();
windowInfoTracker
.removeWindowLayoutInfoListener(layoutStateChangeCallback);
}
class LayoutStateChangeCallback implements Consumer<WindowLayoutInfo> {
@Override
public void accept(WindowLayoutInfo newLayoutInfo) {
SplitLayoutActivity.this.runOnUiThread( () -> {
// Use newLayoutInfo to update the layout.
});
}
}
}
پشتیبانی از RxJava
اگر از RxJava
(نسخه 2
یا 3
) استفاده می کنید، می توانید از مصنوعاتی استفاده کنید که به شما امکان می دهد از Observable
یا Flowable
برای جمع آوری به روز رسانی های WindowLayoutInfo
بدون استفاده از جریان Kotlin استفاده کنید.
لایه سازگاری ارائه شده توسط وابستگیهای androidx.window:window-rxjava2
و androidx.window:window-rxjava3
شامل متدهای WindowInfoTracker#windowLayoutInfoFlowable()
و WindowInfoTracker#windowLayoutInfoObservable()
میشود که به روز رسانی، برنامه را برای WindowLayoutInfo
میتواند دریافت کند.
class RxActivity: AppCompatActivity {
private lateinit var binding: ActivityRxBinding
private var disposable: Disposable? = null
private lateinit var observable: Observable<WindowLayoutInfo>
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivitySplitLayoutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// Create a new observable.
observable = WindowInfoTracker.getOrCreate(this@RxActivity)
.windowLayoutInfoObservable(this@RxActivity)
}
@Override
protected void onStart() {
super.onStart();
// Subscribe to receive WindowLayoutInfo updates.
disposable?.dispose()
disposable = observable
.observeOn(AndroidSchedulers.mainThread())
.subscribe { newLayoutInfo ->
// Use newLayoutInfo to update the layout.
}
}
@Override
protected void onStop() {
super.onStop();
// Dispose of the WindowLayoutInfo observable.
disposable?.dispose()
}
}
ویژگی های نمایشگرهای تاشو
کلاس WindowLayoutInfo
از Jetpack WindowManager ویژگی های یک پنجره نمایش را به عنوان لیستی از عناصر DisplayFeature
در دسترس قرار می دهد.
FoldingFeature
نوعی از DisplayFeature
است که اطلاعاتی در مورد نمایشگرهای تاشو ارائه می دهد، از جمله موارد زیر:
state
: حالت تا شده دستگاه،FLAT
یاHALF_OPENED
orientation
: جهت چین یا لولا،HORIZONTAL
یاVERTICAL
occlusionType
: چه تاشو یا لولا قسمتی از نمایشگر را پنهان کند،NONE
یاFULL
isSeparating
: این که آیا تاشو یا لولا دو ناحیه نمایش منطقی ایجاد می کند، درست یا نادرست
یک دستگاه تاشو که HALF_OPENED
است همیشه isSeparating
به عنوان درست گزارش می دهد زیرا صفحه نمایش به دو ناحیه نمایشگر جدا شده است. همچنین، زمانی که برنامه در هر دو صفحه باشد، isSeparating
همیشه در دستگاههای دو صفحهنمایش صادق است.
ویژگی FoldingFeature
bounds
(که از DisplayFeature
به ارث رسیده است) مستطیل محدود کننده یک ویژگی تاشو مانند یک تا یا لولا را نشان می دهد. از کران ها می توان برای قرار دادن عناصر روی صفحه نسبت به ویژگی استفاده کرد:
کاتلین
override fun onCreate(savedInstanceState: Bundle?) { ... lifecycleScope.launch(Dispatchers.Main) { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { // Safely collects from WindowInfoTracker when the lifecycle is // STARTED and stops collection when the lifecycle is STOPPED. WindowInfoTracker.getOrCreate(this@MainActivity) .windowLayoutInfo(this@MainActivity) .collect { layoutInfo -> // New posture information. val foldingFeature = layoutInfo.displayFeatures .filterIsInstance<FoldingFeature>() .firstOrNull() // Use information from the foldingFeature object. } } } }
جاوا
private WindowInfoTrackerCallbackAdapter windowInfoTracker; private final LayoutStateChangeCallback layoutStateChangeCallback = new LayoutStateChangeCallback(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { ... windowInfoTracker = new WindowInfoTrackerCallbackAdapter(WindowInfoTracker.getOrCreate(this)); } @Override protected void onStart() { super.onStart(); windowInfoTracker.addWindowLayoutInfoListener( this, Runnable::run, layoutStateChangeCallback); } @Override protected void onStop() { super.onStop(); windowInfoTracker.removeWindowLayoutInfoListener(layoutStateChangeCallback); } class LayoutStateChangeCallback implements Consumer<WindowLayoutInfo> { @Override public void accept(WindowLayoutInfo newLayoutInfo) { // Use newLayoutInfo to update the Layout. List<DisplayFeature> displayFeatures = newLayoutInfo.getDisplayFeatures(); for (DisplayFeature feature : displayFeatures) { if (feature instanceof FoldingFeature) { // Use information from the feature object. } } } }
وضعیت روی میز
با استفاده از اطلاعات موجود در شی FoldingFeature
، برنامه شما میتواند از حالتهایی مانند رومیزی پشتیبانی کند، جایی که تلفن روی یک سطح قرار میگیرد، لولا در حالت افقی قرار دارد و صفحه نمایش تاشو نیمه باز است.
وضعیت قرارگیری روی میز به کاربران این امکان را می دهد که با تلفن خود بدون گرفتن گوشی در دستان خود کار کنند. وضعیت قرارگیری روی میز برای تماشای رسانه، گرفتن عکس و برقراری تماس ویدیویی عالی است.
FoldingFeature.State
و FoldingFeature.Orientation
برای تعیین اینکه آیا دستگاه در وضعیت رومیزی قرار دارد یا خیر استفاده کنید:
کاتلین
fun isTableTopPosture(foldFeature : FoldingFeature?) : Boolean { contract { returns(true) implies (foldFeature != null) } return foldFeature?.state == FoldingFeature.State.HALF_OPENED && foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL }
جاوا
boolean isTableTopPosture(FoldingFeature foldFeature) { return (foldFeature != null) && (foldFeature.getState() == FoldingFeature.State.HALF_OPENED) && (foldFeature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL); }
هنگامی که متوجه شدید که دستگاه در وضعیت رومیزی قرار دارد، طرح بندی برنامه خود را مطابق با آن به روز کنید. برای برنامههای رسانه، این معمولاً به معنای قرار دادن پخش در بالای صفحه و کنترلهای موقعیتیابی و محتوای تکمیلی درست در زیر آن برای تماشای هندزفری یا تجربه گوش دادن است.
در Android 15 (سطح API 35) و بالاتر، میتوانید یک API همزمان را فراخوانی کنید تا تشخیص دهید که آیا دستگاه بدون توجه به وضعیت فعلی دستگاه، از حالت رومیزی پشتیبانی میکند یا خیر.
API لیستی از وضعیت های مورد حمایت دستگاه را ارائه می دهد. اگر فهرست حاوی وضعیت قرارگیری روی میز باشد، میتوانید طرحبندی برنامهتان را برای پشتیبانی از وضعیت بدن تقسیم کنید و آزمایشهای A/B را در رابط کاربری برنامهتان برای چیدمانهای روی میز و تمام صفحه اجرا کنید.
کاتلین
if (WindowSdkExtensions.getInstance().extensionsVersion >= 6) { val postures = WindowInfoTracker.getOrCreate(context).supportedPostures if (postures.contains(TABLE_TOP)) { // Device supports tabletop posture. } }
جاوا
if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 6) { List<SupportedPosture> postures = WindowInfoTracker.getOrCreate(context).getSupportedPostures(); if (postures.contains(SupportedPosture.TABLETOP)) { // Device supports tabletop posture. } }
نمونه ها
برنامه
MediaPlayerActivity
: نحوه استفاده از Media3 Exoplayer و WindowManager را برای ایجاد یک پخش کننده ویدیویی تاشو ببینید.برنامه دوربین خود را در دستگاههای تاشو با نرمافزار Jetpack WindowManager بهینه کنید : نحوه پیادهسازی وضعیت روی میز برای برنامههای عکاسی را بیاموزید. منظره یاب را در نیمه بالایی صفحه (بالای تاشو) و کنترل ها را در نیمه پایین (زیر تاشو) نشان دهید.
وضعیت کتاب
یکی دیگر از ویژگی های منحصر به فرد تاشو، حالت کتاب است، جایی که دستگاه نیمه باز است و لولا عمودی است. حالت کتاب برای خواندن کتاب های الکترونیکی عالی است. با طرحبندی دو صفحهای روی صفحهنمایش بزرگ با قابلیت تاشو مانند کتاب صحافی شده، وضعیت کتاب تجربه خواندن یک کتاب واقعی را به تصویر میکشد.
اگر میخواهید هنگام عکسبرداری بدون هندز، نسبت ابعاد متفاوتی را ثبت کنید، میتواند برای عکاسی نیز استفاده شود.
وضعیت قرارگیری کتاب را با همان تکنیک هایی که برای وضعیت قرارگیری روی میز استفاده می شود، اجرا کنید. تنها تفاوت این است که کد باید بررسی کند که جهت ویژگی تاشو به جای افقی عمودی باشد:
کاتلین
fun isBookPosture(foldFeature : FoldingFeature?) : Boolean { contract { returns(true) implies (foldFeature != null) } return foldFeature?.state == FoldingFeature.State.HALF_OPENED && foldFeature.orientation == FoldingFeature.Orientation.VERTICAL }
جاوا
boolean isBookPosture(FoldingFeature foldFeature) { return (foldFeature != null) && (foldFeature.getState() == FoldingFeature.State.HALF_OPENED) && (foldFeature.getOrientation() == FoldingFeature.Orientation.VERTICAL); }
اندازه پنجره تغییر می کند
ناحیه نمایش یک برنامه میتواند در نتیجه تغییر پیکربندی دستگاه تغییر کند، مثلاً وقتی دستگاه تا شده یا باز میشود، میچرخد یا اندازه یک پنجره در حالت چند پنجرهای تغییر میکند.
کلاس Jetpack WindowManager WindowMetricsCalculator
شما را قادر می سازد تا معیارهای فعلی و حداکثر پنجره را بازیابی کنید. مانند پلتفرم WindowMetrics
که در سطح API 30 معرفی شده است، WindowManager WindowMetrics
محدودیت های پنجره را ارائه می دهد، اما API تا سطح API 14 سازگار است.
به استفاده از کلاس های اندازه پنجره مراجعه کنید.
منابع اضافی
نمونه ها
- Jetpack WindowManager : مثالی از نحوه استفاده از کتابخانه Jetpack WindowManager
- Jetcaster : اجرای وضعیت قرارگیری روی میز با Compose
Codelabs
- با Jetpack WindowManager از دستگاه های تاشو و دو صفحه پشتیبانی کنید
- برنامه دوربین خود را در دستگاه های تاشو با Jetpack WindowManager بهینه کنید