فولد برنامه خود را آگاه کنید

نمایشگرهای تاشو بزرگ و حالت‌های تا شده منحصر به فرد، تجربه کاربری جدیدی را در دستگاه‌های تاشو امکان‌پذیر می‌سازد. برای آگاه کردن برنامه خود، از کتابخانه Jetpack WindowManager استفاده کنید، که یک سطح API برای ویژگی‌های پنجره دستگاه تاشو مانند تا و لولا ارائه می‌دهد. وقتی برنامه شما از تا کردن آگاه باشد، می‌تواند طرح‌بندی خود را برای جلوگیری از قرار دادن محتوای مهم در ناحیه چین‌ها یا لولاها تنظیم کند و از چین‌ها و لولاها به عنوان جداکننده طبیعی استفاده کند.

اطلاعات پنجره

رابط WindowInfoTracker در Jetpack WindowManager اطلاعات طرح بندی پنجره را در معرض دید قرار می دهد. متد windowLayoutInfo() واسط جریانی از داده‌های WindowLayoutInfo را برمی‌گرداند که برنامه شما را در مورد وضعیت فولد دستگاه تاشو مطلع می‌کند. متد WindowInfoTracker getOrCreate() نمونه ای از WindowInfoTracker را ایجاد می کند.

WindowManager برای جمع آوری داده های WindowLayoutInfo با استفاده از Kotlin Flow و 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 Flow جمع‌آوری کنید. این آرتیفکت شامل کلاس 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 Flow استفاده کنید.

لایه سازگاری ارائه شده توسط وابستگی‌های 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 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 windowInfoRepo 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()
                        .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);
}

هنگامی که متوجه شدید دستگاه در حالت رومیزی است، طرح بندی برنامه خود را مطابق با آن به روز کنید. برای برنامه‌های رسانه، این معمولاً به معنای قرار دادن پخش در بالای صفحه و کنترل‌های موقعیت‌یابی و محتوای تکمیلی در زیر آن است تا تجربه تماشا یا گوش دادن بدون هندز را داشته باشید.

نمونه ها

  • برنامه MediaPlayerActivity : نحوه استفاده از Media3 Exoplayer و 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

{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}