تعبیه فعالیت، برنامهها را در دستگاههای صفحهنمایش بزرگ با تقسیم پنجره کار برنامه بین دو فعالیت یا دو نمونه از یک فعالیت بهینه میکند.
اگر برنامه شما از چندین فعالیت تشکیل شده است، جاسازی فعالیت به شما امکان میدهد تجربه کاربری پیشرفتهتری را در رایانههای لوحی، دستگاههای تاشو، و دستگاههای ChromeOS ارائه دهید.
جاسازی فعالیت نیازی به بازآفرینی کد ندارد. شما با ایجاد یک فایل پیکربندی XML یا با برقراری تماسهای Jetpack WindowManager API تعیین میکنید که چگونه برنامهتان فعالیتهای خود را نمایش میدهد - کنار هم یا پشتهای.
پشتیبانی از صفحه نمایش های کوچک به صورت خودکار حفظ می شود. هنگامی که برنامه شما روی دستگاهی با صفحه نمایش کوچک است، فعالیت ها یکی روی دیگری قرار می گیرند. در صفحه های بزرگ، فعالیت ها در کنار هم نمایش داده می شوند. سیستم ارائه را بر اساس پیکربندی که ایجاد کردهاید تعیین میکند—بدون نیاز به منطق انشعاب.
تعبیه فعالیتها تغییرات جهتگیری دستگاه را در خود جای میدهد و بهطور یکپارچه روی دستگاههای تاشو کار میکند، فعالیتها را همزمان با تا شدن و باز شدن دستگاه، انباشته و جدا میکند.
جاسازی فعالیت در اکثر دستگاههای دارای صفحه نمایش بزرگ دارای Android 12L (سطح API 32) و بالاتر پشتیبانی میشود.
تقسیم پنجره وظیفه
تعبیه فعالیت، پنجره کار برنامه را به دو ظرف اصلی و ثانویه تقسیم میکند. کانتینرها دارای فعالیت هایی هستند که از فعالیت اصلی یا سایر فعالیت های موجود در کانتینرها راه اندازی شده اند.
فعالیتها هنگام راهاندازی در کانتینر ثانویه انباشته میشوند، و کانتینر ثانویه در بالای کانتینر اصلی در صفحههای کوچک انباشته میشود، بنابراین انباشتن فعالیتها و پیمایش به عقب با ترتیب فعالیتهایی که از قبل در برنامه شما تعبیه شده است، مطابقت دارد.
تعبیه فعالیت به شما امکان می دهد تا فعالیت ها را به روش های مختلف نمایش دهید. برنامه شما میتواند با راهاندازی دو فعالیت در کنار هم، پنجره کار را تقسیم کند:
یا، فعالیتی که کل پنجره کار را اشغال کرده است میتواند با راهاندازی یک فعالیت جدید در کنار:
فعالیت هایی که قبلاً در یک تقسیم و به اشتراک گذاری یک پنجره وظیفه هستند می توانند فعالیت های دیگر را به روش های زیر راه اندازی کنند:
در کنار فعالیت دیگری:
به پهلو، و تقسیم را به طرفین منتقل کنید، فعالیت اولیه قبلی را پنهان کنید:
راه اندازی یک فعالیت در محل در بالا؛ یعنی در همان پشته فعالیت:
یک پنجره کامل فعالیت را در همان کار راه اندازی کنید:
ناوبری برگشتی
انواع مختلف برنامهها بسته به وابستگیهای بین فعالیتها یا نحوه راهاندازی رویداد برگشتی توسط کاربران، میتوانند قوانین پیمایش برگشتی متفاوتی در حالت پنجره وظیفه تقسیمبندی داشته باشند، برای مثال:
- با هم رفتن: اگر فعالیتها مرتبط هستند، و یکی نباید بدون دیگری نشان داده شود، پیمایش برگشتی را میتوان برای تکمیل هر دو پیکربندی کرد.
- به تنهایی: اگر فعالیتها کاملاً مستقل باشند، پیمایش برگشتی در یک فعالیت بر وضعیت فعالیت دیگری در پنجره کار تأثیر نمیگذارد.
هنگام استفاده از پیمایش دکمهای، رویداد برگشت به آخرین فعالیت متمرکز ارسال میشود.
برای پیمایش مبتنی بر اشاره:
Android 14 (سطح API 34) و پایینتر — رویداد برگشتی به فعالیتی که حرکت در آن انجام شده ارسال میشود. وقتی کاربران از سمت چپ صفحه تند تند بکشند، رویداد برگشت به فعالیت در سمت چپ پنجره تقسیم ارسال میشود. هنگامی که کاربران از سمت راست صفحه تند کشیدند، رویداد برگشتی به فعالیت در قسمت سمت راست ارسال میشود.
اندروید 15 (سطح API 35) و بالاتر
وقتی با چندین فعالیت از یک برنامه سروکار دارید، ژست بدون در نظر گرفتن جهت کشیدن انگشت، فعالیت برتر را به پایان میرساند و تجربه یکپارچهتر را ارائه میدهد.
در سناریوهایی که شامل دو فعالیت از برنامههای مختلف است (همپوشانی)، رویداد برگشتی به آخرین فعالیت متمرکز هدایت میشود و با رفتار پیمایش دکمهها همسو میشود.
طرح چند صفحه ای
Jetpack WindowManager شما را قادر میسازد تا در دستگاههای دارای صفحه نمایش بزرگ با Android 12L (سطح API 32) یا بالاتر و در برخی از دستگاههای دارای نسخههای پلتفرم قبلی، فعالیتی را با طرحبندی چند صفحهای ایجاد کنید. برنامههای موجود که بر اساس فعالیتهای متعدد به جای قطعات یا طرحبندیهای مبتنی بر نما هستند، مانند SlidingPaneLayout
میتوانند یک تجربه کاربری بهبودیافته با صفحه نمایش بزرگ بدون تغییر کد منبع ارائه کنند.
یکی از مثالهای رایج تقسیم فهرست-جزئیات است. برای اطمینان از ارائه با کیفیت بالا، سیستم فعالیت لیست را شروع می کند و سپس برنامه بلافاصله فعالیت جزئیات را شروع می کند. سیستم انتقال منتظر می ماند تا هر دو فعالیت ترسیم شوند، سپس آنها را با هم نمایش می دهد. برای کاربر، این دو فعالیت به عنوان یک راه اندازی می شوند.
تقسیم ویژگی ها
شما می توانید تعیین کنید که چگونه پنجره وظیفه بین کانتینرهای تقسیم شده تناسب داشته باشد و چگونه کانتینرها نسبت به یکدیگر چیده شوند.
برای قوانین تعریف شده در یک فایل پیکربندی XML، ویژگی های زیر را تنظیم کنید:
-
splitRatio
: نسبت های ظرف را تنظیم می کند. مقدار یک عدد ممیز شناور در بازه باز (0.0، 1.0) است. -
splitLayoutDirection
: نحوه چیدمان کانتینرهای تقسیم نسبت به یکدیگر را مشخص می کند. ارزش ها عبارتند از:-
ltr
: از چپ به راست -
rtl
: از راست به چپ -
locale
:ltr
یاrtl
از روی تنظیمات محلی تعیین می شود
-
برای مثال به بخش پیکربندی XML مراجعه کنید.
برای قوانین ایجاد شده با استفاده از API های WindowManager، یک شی SplitAttributes
با SplitAttributes.Builder
ایجاد کنید و متدهای سازنده زیر را فراخوانی کنید:
-
setSplitType()
: نسبت کانتینرهای تقسیم را تنظیم می کند. برای آرگومان های معتبر، از جمله متدSplitAttributes.SplitType.ratio()
، بهSplitAttributes.SplitType
مراجعه کنید. setLayoutDirection()
: چیدمان کانتینرها را تنظیم می کند. برای مقادیر ممکن بهSplitAttributes.LayoutDirection
مراجعه کنید.
برای مثال به بخش WindowManager API مراجعه کنید.
متغیرهای
فعالیتهای مکاندار فعالیتهای ثانویه خالی هستند که ناحیهای از یک تقسیم فعالیت را اشغال میکنند. در نهایت قرار است با فعالیت دیگری که حاوی محتوا است جایگزین شوند. به عنوان مثال، یک فعالیت نگهدارنده مکان میتواند سمت ثانویه یک فعالیت تقسیمشده در یک طرحبندی فهرست-جزئیات را اشغال کند تا زمانی که یک مورد از فهرست انتخاب شود، در این مرحله یک فعالیت حاوی اطلاعات جزئیات برای آیتم فهرست انتخابشده جایگزین مکاندار میشود.
بهطور پیشفرض، سیستم مکاندارها را تنها زمانی نمایش میدهد که فضای کافی برای تقسیم فعالیت وجود داشته باشد. هنگامی که اندازه نمایشگر به عرض یا ارتفاع خیلی کوچک برای نمایش یک تقسیم تغییر می کند، متغیرها به طور خودکار تمام می شوند. هنگامی که فضا اجازه می دهد، سیستم مکان نگهدار را با حالت اولیه مجدد راه اندازی می کند.
با این حال، ویژگی stickyPlaceholder
روش SplitPlaceholderRule
یا setSticky()
SplitPlaceholder.Builder
می تواند رفتار پیش فرض را لغو کند. هنگامی که ویژگی یا متد مقدار true
را مشخص می کند، هنگامی که اندازه نمایشگر از یک نمایشگر دو جداره به نمایشگر تک صفحه ای کاهش می یابد، سیستم مکان نگهدار را به عنوان بالاترین فعالیت در پنجره کار نمایش می دهد (برای مثال به پیکربندی تقسیم بندی مراجعه کنید) .
اندازه پنجره تغییر می کند
هنگامی که پیکربندی دستگاه تغییر میکند، عرض پنجره کار را کاهش میدهد تا برای طرحبندی چند صفحهای به اندازه کافی بزرگ نباشد (مثلاً وقتی یک دستگاه تاشو با صفحه بزرگ از اندازه تبلت به اندازه تلفن تا میشود یا اندازه پنجره برنامه در حالت چند پنجرهای تغییر میکند. )، فعالیتهای غیر مکاندار در پنجره ثانویه پنجره وظیفه در بالای فعالیتهای پنجره اصلی قرار میگیرند.
فعالیتهای مکاندار فقط زمانی نشان داده میشوند که عرض نمایش کافی برای تقسیم وجود داشته باشد. در صفحههای کوچکتر، جایبان بهطور خودکار حذف میشود. وقتی ناحیه نمایش دوباره به اندازه کافی بزرگ شد، مکان نگهدار دوباره ایجاد می شود. (به بخش Placeholders مراجعه کنید.)
انباشته کردن فعالیت ها امکان پذیر است زیرا WindowManager فعالیت های موجود در پنجره ثانویه را در بالای فعالیت ها در پنجره اصلی مرتب می کند.
چندین فعالیت در پنجره ثانویه
اکتیویتی B فعالیت C را در جای خود و بدون پرچم های قصد اضافی شروع می کند:
که منجر به ترتیب z زیر از فعالیت ها در همان کار می شود:
بنابراین، در یک پنجره کار کوچکتر، برنامه به یک فعالیت با C در بالای پشته کوچک می شود:
پیمایش به عقب در پنجره کوچکتر از طریق فعالیت هایی که روی هم چیده شده اند هدایت می شود.
اگر پیکربندی پنجره کار به اندازه بزرگتر بازیابی شود که بتواند چندین پنجره را در خود جای دهد، فعالیت ها دوباره در کنار هم نمایش داده می شوند.
تقسیم های انباشته
فعالیت B فعالیت C را به طرفین شروع می کند و تقسیم را به طرفین تغییر می دهد:
نتیجه، ترتیب z فعالیتهای زیر در همان کار است:
در یک پنجره کار کوچکتر، برنامه به یک فعالیت منفرد با C در بالا کوچک می شود:
جهت گیری پرتره ثابت
تنظیم مانیفست android:screenOrientation به برنامه ها امکان می دهد فعالیت ها را به جهت گیری عمودی یا افقی محدود کنند. برای بهبود تجربه کاربری در دستگاههای صفحهنمایش بزرگ مانند تبلتها و تاشوها، سازندگان دستگاه (OEM) میتوانند درخواستهای جهتگیری صفحه را نادیده بگیرند و برنامه را در جهت عمودی در نمایشگرهای افقی یا جهت افقی در نمایشگرهای عمودی را نادیده بگیرند.
به طور مشابه، هنگامی که تعبیه فعالیت فعال است، OEM ها می توانند دستگاه ها را برای فعالیت های پرتره ثابت صندوق نامه در جهت افقی روی صفحه نمایش های بزرگ (عرض ≥ 600dp) سفارشی کنند. هنگامی که یک فعالیت پرتره ثابت فعالیت دوم را راه اندازی می کند، دستگاه می تواند دو فعالیت را در کنار هم در یک نمایشگر دو صفحه نمایش دهد.
همیشه ویژگی android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
را به فایل مانیفست برنامه خود اضافه کنید تا به دستگاهها اطلاع دهید که برنامه شما از جاسازی فعالیت پشتیبانی میکند (بخش پیکربندی تقسیم را ببینید). سپس دستگاههای سفارشیسازیشده OEM میتوانند تعیین کنند که آیا فعالیتهای پرتره ثابت در صندوق پست انجام شود یا خیر.
پیکربندی تقسیم
قوانین تقسیم، تقسیمهای فعالیت را پیکربندی میکنند. شما قوانین تقسیم را در یک فایل پیکربندی XML یا با برقراری تماس های Jetpack WindowManager API تعریف می کنید.
در هر صورت، برنامه شما باید به کتابخانه WindowManager دسترسی داشته باشد و باید به سیستم اطلاع دهد که برنامه جاسازی فعالیت را اجرا کرده است.
موارد زیر را انجام دهید:
به عنوان مثال، آخرین وابستگی کتابخانه WindowManager را به فایل
build.gradle
در سطح ماژول برنامه خود اضافه کنید:implementation 'androidx.window:window:1.1.0-beta02'
کتابخانه WindowManager تمام اجزای مورد نیاز برای تعبیه فعالیت را فراهم می کند.
به سیستم اطلاع دهید که برنامه شما جاسازی فعالیت را اجرا کرده است.
ویژگی
android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
را به عنصر <application> فایل مانیفست برنامه اضافه کنید و مقدار را روی true تنظیم کنید، برای مثال:<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application> <property android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED" android:value="true" /> </application> </manifest>
در نسخه 1.1.0-alpha06 و نسخههای بعدی WindowManager، تقسیمهای جاسازی فعالیت غیرفعال میشوند، مگر اینکه ویژگی به مانیفست اضافه شود و روی true تنظیم شود.
همچنین، سازندگان دستگاه از این تنظیم برای فعال کردن قابلیتهای سفارشی برای برنامههایی که از جاسازی فعالیت پشتیبانی میکنند، استفاده میکنند. به عنوان مثال، دستگاهها میتوانند یک فعالیت فقط عمودی در نمایشگرهای افقی را صندوقدار کنند تا هنگام شروع فعالیت دوم، فعالیت را برای انتقال به یک طرحبندی دو جداره جهتدهی کنند ( به جهتگیری عمودی ثابت مراجعه کنید).
پیکربندی XML
برای ایجاد یک پیاده سازی مبتنی بر XML از تعبیه فعالیت، مراحل زیر را کامل کنید:
یک فایل منبع XML ایجاد کنید که کارهای زیر را انجام دهد:
- فعالیت هایی را تعریف می کند که یک تقسیم را به اشتراک می گذارند
- گزینه های تقسیم را پیکربندی می کند
- هنگامی که محتوا در دسترس نیست، یک مکان نگهدار برای ظرف ثانویه تقسیم ایجاد می کند
- فعالیت هایی را مشخص می کند که هرگز نباید بخشی از یک تقسیم شوند
به عنوان مثال:
<!-- main_split_config.xml --> <resources xmlns:window="http://schemas.android.com/apk/res-auto"> <!-- Define a split for the named activities. --> <SplitPairRule window:splitRatio="0.33" window:splitLayoutDirection="locale" window:splitMinWidthDp="840" window:splitMaxAspectRatioInPortrait="alwaysAllow" window:finishPrimaryWithSecondary="never" window:finishSecondaryWithPrimary="always" window:clearTop="false"> <SplitPairFilter window:primaryActivityName=".ListActivity" window:secondaryActivityName=".DetailActivity"/> </SplitPairRule> <!-- Specify a placeholder for the secondary container when content is not available. --> <SplitPlaceholderRule window:placeholderActivityName=".PlaceholderActivity" window:splitRatio="0.33" window:splitLayoutDirection="locale" window:splitMinWidthDp="840" window:splitMaxAspectRatioInPortrait="alwaysAllow" window:stickyPlaceholder="false"> <ActivityFilter window:activityName=".ListActivity"/> </SplitPlaceholderRule> <!-- Define activities that should never be part of a split. Note: Takes precedence over other split rules for the activity named in the rule. --> <ActivityRule window:alwaysExpand="true"> <ActivityFilter window:activityName=".ExpandedActivity"/> </ActivityRule> </resources>
یک اولیه ساز ایجاد کنید.
جزء WindowManager
RuleController
فایل پیکربندی XML را تجزیه می کند و قوانین را در دسترس سیستم قرار می دهد. یکInitializer
کتابخانه راهاندازی Jetpack، فایل XML را در هنگام راهاندازی برنامه در دسترسRuleController
قرار میدهد تا هنگام شروع هر فعالیتی، قوانین اعمال شوند.برای ایجاد یک مقداردهی اولیه، موارد زیر را انجام دهید:
به عنوان مثال، آخرین وابستگی کتابخانه Jetpack Startup را به فایل
build.gradle
در سطح ماژول خود اضافه کنید:implementation 'androidx.startup:startup-runtime:1.1.1'
کلاسی ایجاد کنید که رابط
Initializer
را پیاده سازی کند.Initializer با ارسال شناسه فایل پیکربندی XML (
main_split_config.xml
) به روشRuleController.parseRules()
قوانین تقسیم را در دسترسRuleController
قرار می دهد.کاتلین
class SplitInitializer : Initializer<RuleController> { override fun create(context: Context): RuleController { return RuleController.getInstance(context).apply { setRules(RuleController.parseRules(context, R.xml.main_split_config)) } } override fun dependencies(): List<Class<out Initializer<*>>> { return emptyList() } }
جاوا
public class SplitInitializer implements Initializer<RuleController> { @NonNull @Override public RuleController create(@NonNull Context context) { RuleController ruleController = RuleController.getInstance(context); ruleController.setRules( RuleController.parseRules(context, R.xml.main_split_config) ); return ruleController; } @NonNull @Override public List<Class<? extends Initializer<?>>> dependencies() { return Collections.emptyList(); } }
یک ارائه دهنده محتوا برای تعاریف قوانین ایجاد کنید.
androidx.startup.InitializationProvider
به عنوان<provider>
به فایل مانیفست برنامه خود اضافه کنید. یک ارجاع به اجرای اولیه سازRuleController
خود،SplitInitializer
اضافه کنید:<!-- AndroidManifest.xml --> <provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <!-- Make SplitInitializer discoverable by InitializationProvider. --> <meta-data android:name="${applicationId}.SplitInitializer" android:value="androidx.startup" /> </provider>
InitializationProvider
قبل از فراخوانی متدonCreate()
برنامهSplitInitializer
کشف و مقداردهی اولیه می کند. در نتیجه، زمانی که فعالیت اصلی برنامه شروع می شود، قوانین تقسیم اعمال می شوند.
WindowManager API
میتوانید با تعداد انگشت شماری تماس API، تعبیه فعالیت را به صورت برنامهریزی اجرا کنید. فراخوانی ها را در متد onCreate()
یک زیر کلاس از Application
انجام دهید تا مطمئن شوید که قوانین قبل از شروع هر فعالیتی قابل اجرا هستند.
برای ایجاد یک تقسیم فعالیت به صورت برنامهریزی شده، موارد زیر را انجام دهید:
ایجاد یک قانون تقسیم:
یک
SplitPairFilter
ایجاد کنید که فعالیت هایی را که تقسیم را به اشتراک می گذارند شناسایی می کند:کاتلین
val splitPairFilter = SplitPairFilter( ComponentName(this, ListActivity::class.java), ComponentName(this, DetailActivity::class.java), null )
جاوا
SplitPairFilter splitPairFilter = new SplitPairFilter( new ComponentName(this, ListActivity.class), new ComponentName(this, DetailActivity.class), null );
فیلتر را به مجموعه فیلتر اضافه کنید:
کاتلین
val filterSet = setOf(splitPairFilter)
جاوا
Set<SplitPairFilter> filterSet = new HashSet<>(); filterSet.add(splitPairFilter);
ایجاد ویژگی های طرح بندی برای تقسیم:
کاتلین
val splitAttributes: SplitAttributes = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build()
جاوا
final SplitAttributes splitAttributes = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build();
SplitAttributes.Builder
یک شی حاوی ویژگی های طرح بندی ایجاد می کند:-
setSplitType()
: نحوه تخصیص ناحیه نمایش موجود به هر کانتینر فعالیت را مشخص می کند. نوع تقسیم نسبت، نسبت ناحیه نمایش موجود را که به ظرف اولیه اختصاص داده شده است، مشخص می کند. ظرف ثانویه باقیمانده منطقه نمایش موجود را اشغال می کند. -
setLayoutDirection()
: نحوه چیدمان کانتینرهای اکتیویتی را نسبت به یکدیگر مشخص می کند، ابتدا کانتینر اصلی.
-
یک
SplitPairRule
بسازید:کاتلین
val splitPairRule = SplitPairRule.Builder(filterSet) .setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER) .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS) .setClearTop(false) .build()
جاوا
SplitPairRule splitPairRule = new SplitPairRule.Builder(filterSet) .setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER) .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS) .setClearTop(false) .build();
SplitPairRule.Builder
قانون را ایجاد و پیکربندی می کند:-
filterSet
: حاوی فیلترهای جفت تقسیم شده است که با شناسایی فعالیت هایی که یک تقسیم را به اشتراک می گذارند، تعیین می کند که چه زمانی قانون اعمال شود. -
setDefaultSplitAttributes()
: ویژگی های layout را به قانون اعمال می کند. -
setMinWidthDp()
: حداقل عرض نمایش (بر حسب پیکسلهای مستقل از چگالی، dp) را تنظیم میکند که تقسیم را فعال میکند. -
setMinSmallestWidthDp()
: حداقل مقداری را (بر حسب dp) تنظیم می کند که ابعاد کوچکتر از دو بعد نمایشگر برای فعال کردن یک تقسیم بدون توجه به جهت دستگاه باید داشته باشد. -
setMaxAspectRatioInPortrait()
: حداکثر نسبت ابعاد نمایش (ارتفاع:عرض) را در جهت عمودی که تقسیم فعالیت برای آن نمایش داده می شود را تنظیم می کند. اگر نسبت تصویر یک نمایشگر عمودی از حداکثر نسبت تصویر بیشتر شود، بدون توجه به عرض نمایشگر، تقسیمبندی غیرفعال میشود. توجه: مقدار پیشفرض 1.4 است که باعث میشود فعالیتها کل پنجره کار را در جهت عمودی در اکثر تبلتها اشغال کنند.SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
وsetMaxAspectRatioInLandscape()
نیز ببینید. مقدار پیشفرض برای LandscapeALWAYS_ALLOW
است. -
setFinishPrimaryWithSecondary()
: تعیین می کند که چگونه تمام کردن تمام فعالیت ها در کانتینر ثانویه بر فعالیت ها در کانتینر اصلی تأثیر می گذارد.NEVER
نشان نمیدهد که سیستم نباید فعالیتهای اولیه را در زمانی که تمام فعالیتها در کانتینر ثانویه تمام میشوند به پایان برساند ( به پایان فعالیتها مراجعه کنید). -
setFinishSecondaryWithPrimary()
: تعیین می کند که چگونه تمام کردن تمام فعالیت ها در کانتینر اصلی بر فعالیت های کانتینر ثانویه تأثیر می گذارد.ALWAYS
نشان میدهد که سیستم باید همیشه فعالیتها را در کانتینر ثانویه پایان دهد، زمانی که همه فعالیتها در ظرف اولیه تمام میشوند ( به پایان فعالیتها مراجعه کنید). -
setClearTop()
: مشخص می کند که آیا تمام فعالیت ها در کانتینر ثانویه زمانی که یک اکتیویتی جدید در کانتینر راه اندازی می شود به پایان می رسد یا خیر. یک مقدارfalse
مشخص میکند که فعالیتهای جدید در بالای فعالیتهایی که از قبل در کانتینر ثانویه قرار دارند، انباشته میشوند.
-
نمونه singleton از WindowManager
RuleController
را دریافت کنید و قانون را اضافه کنید:کاتلین
val ruleController = RuleController.getInstance(this) ruleController.addRule(splitPairRule)
جاوا
RuleController ruleController = RuleController.getInstance(this); ruleController.addRule(splitPairRule);
هنگامی که محتوا در دسترس نیست، یک مکان نگهدار برای ظرف ثانویه ایجاد کنید:
یک
ActivityFilter
ایجاد کنید که فعالیتی را که نگهدارنده مکان یک تقسیم پنجره وظیفه را با آن به اشتراک می گذارد، شناسایی می کند:کاتلین
val placeholderActivityFilter = ActivityFilter( ComponentName(this, ListActivity::class.java), null )
جاوا
ActivityFilter placeholderActivityFilter = new ActivityFilter( new ComponentName(this, ListActivity.class), null );
فیلتر را به مجموعه فیلتر اضافه کنید:
کاتلین
val placeholderActivityFilterSet = setOf(placeholderActivityFilter)
جاوا
Set<ActivityFilter> placeholderActivityFilterSet = new HashSet<>(); placeholderActivityFilterSet.add(placeholderActivityFilter);
یک
SplitPlaceholderRule
ایجاد کنید:کاتلین
val splitPlaceholderRule = SplitPlaceholderRule.Builder( placeholderActivityFilterSet, Intent(context, PlaceholderActivity::class.java) ).setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS) .setSticky(false) .build()
جاوا
SplitPlaceholderRule splitPlaceholderRule = new SplitPlaceholderRule.Builder( placeholderActivityFilterSet, new Intent(context, PlaceholderActivity.class) ).setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS) .setSticky(false) .build();
SplitPlaceholderRule.Builder
قانون را ایجاد و پیکربندی می کند:-
placeholderActivityFilterSet
: حاوی فیلترهای فعالیت است که با شناسایی فعالیت هایی که فعالیت نگهدارنده مکان با آنها مرتبط است، تعیین می کند که چه زمانی قانون اعمال شود. -
Intent
: راه اندازی فعالیت نگهدارنده مکان را مشخص می کند. -
setDefaultSplitAttributes()
: ویژگی های layout را به قانون اعمال می کند. -
setMinWidthDp()
: حداقل عرض نمایش (برحسب پیکسل های مستقل از چگالی، dp) را تنظیم می کند که امکان تقسیم را فراهم می کند. -
setMinSmallestWidthDp()
: حداقل مقداری را (بر حسب dp) تنظیم می کند که ابعاد کوچکتر از دو بعد نمایشگر باید داشته باشد تا اجازه تقسیم بدون توجه به جهت دستگاه را بدهد. -
setMaxAspectRatioInPortrait()
: حداکثر نسبت ابعاد نمایش (ارتفاع:عرض) را در جهت عمودی که تقسیم فعالیت برای آن نمایش داده می شود را تنظیم می کند. توجه: مقدار پیشفرض 1.4 است که منجر به پر کردن فعالیتها در پنجره کار در جهت عمودی در اکثر تبلتها میشود.SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
وsetMaxAspectRatioInLandscape()
نیز ببینید. مقدار پیشفرض برای LandscapeALWAYS_ALLOW
است. -
setFinishPrimaryWithPlaceholder()
: تعیین می کند که چگونه اتمام فعالیت محل نگهدارنده بر روی فعالیت ها در ظرف اصلی تأثیر می گذارد. ALWAYS نشان میدهد که سیستم باید همیشه فعالیتها را در محفظه اولیه زمانی که نگهدارنده به پایان میرسد پایان دهد ( به پایان فعالیتها مراجعه کنید). -
setSticky()
: تعیین می کند که آیا پس از اینکه مکان نگهدار برای اولین بار در یک تقسیم با حداقل عرض کافی ظاهر شد، فعالیت مکان نگهدار در بالای پشته فعالیت در نمایشگرهای کوچک ظاهر شود یا خیر.
-
قانون را به
RuleController
WindowManager اضافه کنید:کاتلین
ruleController.addRule(splitPlaceholderRule)
جاوا
ruleController.addRule(splitPlaceholderRule);
فعالیت هایی را مشخص کنید که هرگز نباید بخشی از یک تقسیم شوند:
یک
ActivityFilter
ایجاد کنید که فعالیتی را مشخص می کند که همیشه باید کل منطقه نمایش کار را اشغال کند:کاتلین
val expandedActivityFilter = ActivityFilter( ComponentName(this, ExpandedActivity::class.java), null )
جاوا
ActivityFilter expandedActivityFilter = new ActivityFilter( new ComponentName(this, ExpandedActivity.class), null );
فیلتر را به مجموعه فیلتر اضافه کنید:
کاتلین
val expandedActivityFilterSet = setOf(expandedActivityFilter)
جاوا
Set<ActivityFilter> expandedActivityFilterSet = new HashSet<>(); expandedActivityFilterSet.add(expandedActivityFilter);
یک
ActivityRule
ایجاد کنید:کاتلین
val activityRule = ActivityRule.Builder(expandedActivityFilterSet) .setAlwaysExpand(true) .build()
جاوا
ActivityRule activityRule = new ActivityRule.Builder( expandedActivityFilterSet ).setAlwaysExpand(true) .build();
ActivityRule.Builder
قانون را ایجاد و پیکربندی می کند:-
expandedActivityFilterSet
: حاوی فیلترهای فعالیت است که تعیین می کند با شناسایی فعالیت هایی که می خواهید از تقسیم ها حذف شوند، چه زمانی قانون اعمال شود. -
setAlwaysExpand()
: مشخص می کند که آیا اکتیویتی باید کل پنجره وظیفه را پر کند یا خیر.
-
قانون را به
RuleController
WindowManager اضافه کنید:کاتلین
ruleController.addRule(activityRule)
جاوا
ruleController.addRule(activityRule);
تعبیه برنامه های متقابل
در Android 13 (سطح API 33) و بالاتر، برنامهها میتوانند فعالیتهای برنامههای دیگر را جاسازی کنند. تعبیه فعالیت های متقابل یا متقاطع UID ، یکپارچه سازی بصری فعالیت ها از چندین برنامه Android را امکان پذیر می کند. سیستم یک فعالیت برنامه میزبان و یک فعالیت جاسازی شده از یک برنامه دیگر را در کنار هم یا بالا و پایین صفحه نمایش می دهد، درست مانند جاسازی فعالیت تک برنامه.
به عنوان مثال، برنامه تنظیمات می تواند فعالیت انتخابگر تصویر زمینه را از برنامه WallpaperPicker جاسازی کند:
مدل اعتماد
فرآیندهای میزبانی که فعالیتهای برنامههای دیگر را جاسازی میکنند، میتوانند نمایش فعالیتهای تعبیهشده، از جمله اندازه، موقعیت، برش و شفافیت را دوباره تعریف کنند. میزبان های مخرب می توانند از این قابلیت برای گمراه کردن کاربران و ایجاد کلیک جک یا سایر حملات اصلاح کننده رابط کاربری استفاده کنند.
برای جلوگیری از سوء استفاده از جاسازی فعالیتهای بین برنامهای، Android از برنامهها میخواهد که برای اجازه دادن به جاسازی فعالیتهای خود شرکت کنند. برنامهها میتوانند میزبانها را بهعنوان مورد اعتماد یا غیرقابل اعتماد معرفی کنند.
میزبان های قابل اعتماد
برای اجازه دادن به سایر برنامهها برای جاسازی و کنترل کامل ارائه فعالیتها از برنامه شما، گواهی SHA-256 برنامه میزبان را در ویژگی android:knownActivityEmbeddingCerts
عناصر <activity>
یا <application>
فایل مانیفست برنامه خود مشخص کنید.
مقدار android:knownActivityEmbeddingCerts
را به عنوان یک رشته تنظیم کنید:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@string/known_host_certificate_digest"
... />
یا برای تعیین چندین گواهی، آرایه ای از رشته ها:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@array/known_host_certificate_digests"
... />
که به منبعی مانند زیر ارجاع می دهد:
<resources>
<string-array name="known_host_certificate_digests">
<item>cert1</item>
<item>cert2</item>
...
</string-array>
</resources>
دارندگان برنامه می توانند با اجرای کار Gradle signingReport
خلاصه گواهی SHA را دریافت کنند. خلاصه گواهی اثر انگشت SHA-256 بدون کولون جداکننده است. برای اطلاعات بیشتر، به اجرای گزارش امضا و احراز هویت مشتری مراجعه کنید.
هاست های غیر قابل اعتماد
برای اینکه به هر برنامه ای اجازه دهید فعالیت های برنامه شما را جاسازی کند و نمایش آنها را کنترل کند، ویژگی android:allowUntrustedActivityEmbedding
در عناصر <activity>
یا <application>
در مانیفست برنامه مشخص کنید، به عنوان مثال:
<activity
android:name=".MyEmbeddableActivity"
android:allowUntrustedActivityEmbedding="true"
... />
مقدار پیشفرض ویژگی false است، که از تعبیه فعالیت بین برنامهای جلوگیری میکند.
احراز هویت سفارشی
برای کاهش خطرات تعبیه فعالیت های نامعتبر، یک مکانیسم احراز هویت سفارشی ایجاد کنید که هویت میزبان را تأیید می کند. اگر گواهیهای میزبان را میشناسید، از کتابخانه androidx.security.app.authenticator
برای احراز هویت استفاده کنید. اگر میزبان پس از تعبیه فعالیت شما احراز هویت شود، می توانید محتوای واقعی را نمایش دهید. در غیر این صورت، می توانید به کاربر اطلاع دهید که اقدام مجاز نبوده و محتوا را مسدود کنید.
از متد ActivityEmbeddingController#isActivityEmbedded()
از کتابخانه Jetpack WindowManager برای بررسی اینکه آیا یک میزبان فعالیت شما را تعبیه می کند، استفاده کنید، به عنوان مثال:
کاتلین
fun isActivityEmbedded(activity: Activity): Boolean { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity) }
جاوا
boolean isActivityEmbedded(Activity activity) { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity); }
حداقل محدودیت اندازه
سیستم Android حداقل ارتفاع و عرض مشخص شده در عنصر مانیفست برنامه <layout>
را برای فعالیت های جاسازی شده اعمال می کند. اگر برنامه ای حداقل ارتفاع و عرض را مشخص نکند، مقادیر پیش فرض سیستم اعمال می شود ( sw220dp
).
اگر میزبان سعی کند اندازه ظرف تعبیه شده را به اندازه کوچکتر از حداقل تغییر دهد، ظرف جاسازی شده گسترش می یابد تا کل محدوده کار را اشغال کند.
<activity-alias>
برای اینکه جاسازی فعالیت قابل اعتماد یا غیرقابل اعتماد با عنصر <activity-alias>
کار کند، android:knownActivityEmbeddingCerts
یا android:allowUntrustedActivityEmbedding
باید به جای نام مستعار، برای فعالیت هدف اعمال شود. خط مشی ای که امنیت سرور سیستم را تأیید می کند بر اساس پرچم های تنظیم شده روی هدف است، نه نام مستعار.
برنامه میزبان
برنامه های میزبان، تعبیه فعالیت بین برنامه ای را به همان روشی که تعبیه فعالیت تک برنامه ای را پیاده سازی می کنند، پیاده سازی می کنند. اشیاء SplitPairRule
و SplitPairFilter
یا ActivityRule
و ActivityFilter
فعالیت های تعبیه شده و تقسیم پنجره وظیفه را مشخص می کنند. قوانین تقسیم به صورت ایستا در XML یا در زمان اجرا با استفاده از فراخوانی های Jetpack WindowManager API تعریف می شوند.
اگر یک برنامه میزبان تلاش کند فعالیتی را جاسازی کند که در تعبیه بین برنامه ای شرکت نکرده است، فعالیت کل محدوده کار را اشغال می کند. در نتیجه، برنامه های میزبان باید بدانند که آیا فعالیت های هدف اجازه جاسازی بین برنامه ها را می دهد یا خیر.
اگر یک فعالیت جاسازی شده یک فعالیت جدید را در همان کار شروع کند و فعالیت جدید در جاسازی بین برنامهای شرکت نکرده باشد، این فعالیت به جای پوشاندن فعالیت در ظرف جاسازی شده، کل محدوده کار را اشغال میکند.
یک برنامه میزبان می تواند فعالیت های خود را بدون محدودیت تعبیه کند تا زمانی که فعالیت ها در همان کار راه اندازی شوند.
نمونه های تقسیم شده
تقسیم از پنجره کامل
بدون نیاز به بازسازی مجدد می توانید پیکربندی تقسیم را به صورت ایستا یا در زمان اجرا تعریف کنید و سپس Context#startActivity()
بدون هیچ پارامتر اضافی فراخوانی کنید.
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
تقسیم به طور پیش فرض
وقتی صفحه فرود یک برنامه به گونهای طراحی شده است که در صفحههای بزرگ به دو کانتینر تقسیم شود، تجربه کاربر زمانی بهترین است که هر دو فعالیت به طور همزمان ایجاد و ارائه شوند. با این حال، ممکن است تا زمانی که کاربر با فعالیت در کانتینر اصلی تعامل نداشته باشد، محتوا برای ظرف ثانویه تقسیم در دسترس نباشد (به عنوان مثال، کاربر یک مورد را از منوی پیمایش انتخاب کند). یک فعالیت مکاننما میتواند جای خالی را پر کند تا زمانی که محتوا در ظرف ثانویه تقسیم نمایش داده شود (به بخش Placeholders مراجعه کنید).
برای ایجاد یک تقسیم با یک مکان نگهدار، یک مکان نگهدار ایجاد کنید و آن را با فعالیت اصلی مرتبط کنید:
<SplitPlaceholderRule
window:placeholderActivityName=".PlaceholderActivity">
<ActivityFilter
window:activityName=".MainActivity"/>
</SplitPlaceholderRule>
تقسیم پیوند عمیق
هنگامی که یک برنامه یک هدف دریافت می کند، فعالیت هدف می تواند به عنوان بخش ثانویه یک تقسیم فعالیت نشان داده شود. برای مثال، درخواستی برای نمایش یک صفحه جزئیات با اطلاعات مربوط به یک مورد از یک لیست. در نمایشگرهای کوچک، جزئیات در پنجره کار کامل نشان داده می شود. در دستگاه های بزرگتر، در کنار لیست.
درخواست راه اندازی باید به فعالیت اصلی هدایت شود و فعالیت جزئیات هدف باید به صورت تقسیمی راه اندازی شود. سیستم به طور خودکار بر اساس عرض نمایش موجود، ارائه صحیح را انتخاب می کند - پشته یا کنار هم -.
کاتلین
override fun onCreate(savedInstanceState Bundle?) { . . . RuleController.getInstance(this) .addRule(SplitPairRule.Builder(filterSet).build()) startActivity(Intent(this, DetailActivity::class.java)) }
جاوا
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { . . . RuleController.getInstance(this) .addRule(new SplitPairRule.Builder(filterSet).build()); startActivity(new Intent(this, DetailActivity.class)); }
مقصد پیوند عمیق ممکن است تنها فعالیتی باشد که باید در پشته ناوبری پشتی در دسترس کاربر باشد، و ممکن است بخواهید از رد کردن فعالیت جزئیات و باقی گذاشتن تنها فعالیت اصلی خودداری کنید:
در عوض، میتوانید هر دو فعالیت را همزمان با استفاده از ویژگی finishPrimaryWithSecondary
به پایان برسانید:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".ListActivity"
window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>
بخش تنظیمات پیکربندی را ببینید.
فعالیت های متعدد در کانتینرهای تقسیم شده
قرار دادن چندین فعالیت در یک کانتینر تقسیم شده، کاربران را قادر می سازد به محتوای عمیق دسترسی داشته باشند. به عنوان مثال، با تقسیم جزئیات لیست، کاربر ممکن است نیاز داشته باشد که به بخش جزئیات فرعی برود اما فعالیت اصلی را در جای خود نگه دارد:
کاتلین
class DetailActivity { . . . fun onOpenSubDetail() { startActivity(Intent(this, SubDetailActivity::class.java)) } }
جاوا
public class DetailActivity { . . . void onOpenSubDetail() { startActivity(new Intent(this, SubDetailActivity.class)); } }
فعالیت جزییات فرعی در بالای فعالیت جزئیات قرار می گیرد و آن را پنهان می کند:
سپس کاربر می تواند با پیمایش در پشته به سطح جزئیات قبلی برگردد:
انباشتن فعالیتها روی هم، رفتار پیشفرض زمانی است که فعالیتها از یک فعالیت در یک کانتینر ثانویه راهاندازی میشوند. فعالیتهایی که از کانتینر اولیه در یک تقسیم فعال راهاندازی میشوند نیز به کانتینر ثانویه در بالای پشته فعالیت ختم میشوند.
فعالیت در یک کار جدید
هنگامی که فعالیتها در یک پنجره وظیفه تقسیم فعالیتها را در یک کار جدید شروع میکنند، وظیفه جدید از وظیفهای که شامل تقسیم میشود جدا است و پنجره کامل نمایش داده میشود. صفحه Recents دو کار را نشان می دهد: وظیفه در تقسیم و وظیفه جدید.
جایگزینی فعالیت
فعالیت ها را می توان در پشته کانتینر ثانویه جایگزین کرد. به عنوان مثال، زمانی که فعالیت اولیه برای ناوبری سطح بالا استفاده می شود و فعالیت ثانویه یک مقصد انتخاب شده است. هر انتخاب از پیمایش سطح بالا باید یک فعالیت جدید را در ظرف ثانویه شروع کند و فعالیت یا فعالیت هایی را که قبلاً در آنجا بودند حذف کند.
اگر برنامه زمانی که انتخاب پیمایش تغییر میکند، فعالیت را در محفظه ثانویه به پایان نرساند، ممکن است هنگام جمع کردن تقسیم (زمانی که دستگاه تا شده است، پیمایش برگشت گیج کننده باشد). به عنوان مثال، اگر یک منو در صفحه اصلی دارید و صفحههای A و B را در قسمت ثانویه انباشته دارید، وقتی کاربر گوشی را تا میکند، B بالای A و A بالای منو است. هنگامی که کاربر از B به عقب برمی گردد، A به جای منو ظاهر می شود.
در چنین مواردی صفحه A باید از پشته حذف شود.
رفتار پیشفرض هنگام پرتاب به کنار در یک کانتینر جدید بر روی یک تقسیم موجود این است که کانتینرهای ثانویه جدید را در بالا قرار دهید و کانتینرهای قدیمی را در پشته نگه دارید. میتوانید تقسیمها را طوری پیکربندی کنید که کانتینرهای ثانویه قبلی را با clearTop
پاک کرده و فعالیتهای جدید را به طور معمول راهاندازی کنید.
<SplitPairRule
window:clearTop="true">
<SplitPairFilter
window:primaryActivityName=".Menu"
window:secondaryActivityName=".ScreenA"/>
<SplitPairFilter
window:primaryActivityName=".Menu"
window:secondaryActivityName=".ScreenB"/>
</SplitPairRule>
کاتلین
class MenuActivity { . . . fun onMenuItemSelected(selectedMenuItem: Int) { startActivity(Intent(this, classForItem(selectedMenuItem))) } }
جاوا
public class MenuActivity { . . . void onMenuItemSelected(int selectedMenuItem) { startActivity(new Intent(this, classForItem(selectedMenuItem))); } }
یا از همان اکتیویتی ثانویه استفاده کنید و از فعالیت اصلی (منو) مقاصد جدیدی ارسال کنید که به همان نمونه حل میشوند، اما حالت یا بهروزرسانی رابط کاربری را در ظرف ثانویه راهاندازی میکنند.
تقسیم های متعدد
برنامهها میتوانند با راهاندازی فعالیتهای اضافی در کنار، ناوبری عمیق چند سطحی را ارائه دهند.
هنگامی که یک اکتیویتی در یک کانتینر ثانویه، یک فعالیت جدید را به طرفین راه اندازی می کند، یک تقسیم جدید در بالای تقسیم موجود ایجاد می شود.
پشته پشتی شامل تمام فعالیتهایی است که قبلاً باز شدهاند، بنابراین کاربران میتوانند پس از اتمام C به تقسیم A/B بروند.
برای ایجاد یک تقسیم جدید ، فعالیت جدید را از ظرف ثانویه موجود به طرف آن راه اندازی کنید. تنظیمات را برای هر دو شکاف A/B و B/C اعلام کنید و فعالیت C را به طور عادی از B:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
<SplitPairFilter
window:primaryActivityName=".B"
window:secondaryActivityName=".C"/>
</SplitPairRule>
کاتلین
class B { . . . fun onOpenC() { startActivity(Intent(this, C::class.java)) } }
جاوا
public class B { . . . void onOpenC() { startActivity(new Intent(this, C.class)); } }
واکنش نشان می دهد به تغییرات حالت تقسیم
فعالیت های مختلف در یک برنامه می تواند دارای عناصر UI باشد که عملکرد یکسانی را انجام می دهند. به عنوان مثال ، کنترلی که پنجره ای حاوی تنظیمات حساب را باز می کند.
اگر دو فعالیت که یک عنصر UI مشترک دارند ، در یک تقسیم قرار دارند ، نشان دادن این عنصر در هر دو فعالیت ، زائد و شاید گیج کننده است.
برای دانستن اینکه چه زمانی فعالیت ها در یک تقسیم هستند ، جریان SplitController.splitInfoList
را بررسی کنید یا یک شنونده را با SplitControllerCallbackAdapter
برای تغییر در حالت تقسیم ثبت کنید. سپس ، UI را بر این اساس تنظیم کنید:
کاتلین
val layout = layoutInflater.inflate(R.layout.activity_main, null) val view = layout.findViewById<View>(R.id.infoButton) lifecycleScope.launch { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { splitController.splitInfoList(this@SplitDeviceActivity) // The activity instance. .collect { list -> view.visibility = if (list.isEmpty()) View.VISIBLE else View.GONE } } }
جاوا
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { . . . new SplitControllerCallbackAdapter(SplitController.getInstance(this)) .addSplitListener( this, Runnable::run, splitInfoList -> { View layout = getLayoutInflater().inflate(R.layout.activity_main, null); layout.findViewById(R.id.infoButton).setVisibility( splitInfoList.isEmpty() ? View.VISIBLE : View.GONE); }); }
Coroutines را می توان در هر حالت چرخه عمر راه اندازی کرد ، اما به طور معمول در حالت STARTED
برای حفظ منابع راه اندازی می شود (برای کسب اطلاعات بیشتر به استفاده از Coroutines Kotlin با اجزای آگاه از چرخه عمر مراجعه کنید).
در هر حالت چرخه عمر ، تماس تلفنی را می توان انجام داد ، از جمله هنگامی که یک فعالیت متوقف می شود. شنوندگان معمولاً باید در onStart()
ثبت شوند و در onStop()
ثبت نشده باشند.
معین
برخی از فعالیت ها کاربران را از تعامل با برنامه تا زمانی که یک عمل مشخص انجام شود ، مسدود می کند. به عنوان مثال ، یک فعالیت صفحه نمایش ورود به سیستم ، صفحه تأیید خط مشی یا پیام خطا. از فعالیت های معین باید در یک شکاف جلوگیری شود.
یک فعالیت می تواند مجبور شود همیشه با استفاده از پیکربندی Expand ، پنجره کار را پر کند:
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".FullWidthActivity"/>
</ActivityRule>
فعالیت های پایان
کاربران می توانند با کشیدن از لبه نمایش ، فعالیت های هر دو طرف تقسیم را به پایان برسانند:
اگر دستگاه برای استفاده از دکمه عقب به جای ناوبری ژست تنظیم شده باشد ، ورودی به فعالیت متمرکز ارسال می شود - فعالیتی که آخرین بار لمس شده یا راه اندازی شده است.
تأثیر این که تمام فعالیت ها در یک ظرف بر روی ظرف مخالف قرار دارد ، بستگی به پیکربندی تقسیم دارد.
ویژگی های پیکربندی
شما می توانید ویژگی های قانون جفت تقسیم را برای پیکربندی چگونگی پایان کار تمام فعالیت ها در یک طرف تقسیم بر فعالیت های آن طرف تقسیم تأثیر می گذارد. صفات عبارتند از:
-
window:finishPrimaryWithSecondary
- چگونگی پایان کار تمام فعالیت ها در ظرف ثانویه بر فعالیت های موجود در ظرف اصلی تأثیر می گذارد -
window:finishSecondaryWithPrimary
- چگونگی پایان کار تمام فعالیت ها در کانتینر اصلی بر فعالیت های موجود در ظرف ثانویه تأثیر می گذارد
مقادیر احتمالی ویژگی ها عبارتند از:
-
always
- همیشه فعالیت ها را در ظرف مرتبط به پایان برسانید -
never
- هرگز فعالیت ها را در ظرف مرتبط به پایان نرسانید -
adjacent
- هنگامی که دو ظروف در مجاورت یکدیگر نمایش داده می شوند ، فعالیت ها را در ظرف مرتبط به پایان برسانید ، اما نه وقتی که این دو ظروف جمع شده اند
به عنوان مثال:
<SplitPairRule
<!-- Do not finish primary container activities when all secondary container activities finish. -->
window:finishPrimaryWithSecondary="never"
<!-- Finish secondary container activities when all primary container activities finish. -->
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
پیکربندی پیش فرض
هنگامی که تمام فعالیت ها در یک ظرف یک تقسیم تقسیم ، ظرف باقیمانده کل پنجره را اشغال می کند:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
فعالیت ها را با هم تمام کنید
هنگامی که تمام فعالیت های موجود در ظرف ثانویه به پایان برسد ، فعالیت ها را در ظرف اصلی به طور خودکار به پایان برسانید:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
هنگامی که تمام فعالیت های موجود در ظرف اصلی به پایان برسد ، فعالیت ها را در ظرف ثانویه به طور خودکار به پایان برسانید:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
فعالیت ها را با هم به پایان برسانید وقتی همه فعالیت ها در ظرف اولیه یا ثانویه به پایان برسد:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
چندین فعالیت را در ظروف به پایان برسانید
اگر چندین فعالیت در یک ظرف تقسیم شده جمع شود ، پایان دادن به فعالیت در پایین پشته ، به طور خودکار فعالیت ها را در بالا به پایان نمی رساند.
به عنوان مثال ، اگر دو فعالیت در ظرف ثانویه باشد ، C در بالای B:
و پیکربندی تقسیم با پیکربندی فعالیت های A و B تعریف می شود:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
به پایان رساندن فعالیت برتر ، تقسیم را حفظ می کند.
به پایان رساندن فعالیت پایین (ریشه) ظرف ثانویه ، فعالیت های موجود در آن را از بین نمی برد. و بنابراین ، تقسیم را نیز حفظ می کند.
هرگونه قانون اضافی برای پایان فعالیت در کنار هم ، مانند اتمام فعالیت ثانویه با اولیه ، نیز اجرا می شود:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
و هنگامی که تقسیم پیکربندی شده است تا ابتدایی و ثانویه را با هم به پایان برساند:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
در زمان اجرا ، ویژگی های تقسیم را تغییر دهید
خواص یک تقسیم فعال و قابل مشاهده قابل تغییر نیست. تغییر قوانین تقسیم بر پرتاب فعالیت های اضافی و ظروف جدید تأثیر می گذارد ، اما شکاف های موجود و فعال نیست.
برای تغییر خصوصیات شکاف های فعال ، فعالیت جانبی یا فعالیت های موجود در تقسیم را به پایان برسانید و دوباره با پیکربندی جدید به طرف آن راه اندازی کنید.
خصوصیات تقسیم پویا
Android 15 (API سطح 35) و بالاتر توسط JetPack Windowmanager 1.4 و بالاتر از ویژگی های پویا ارائه می دهد که امکان تنظیم قابلیت های تعبیه شده فعالیت را فراهم می کند ، از جمله:
- گسترش صفحه: یک تقسیم کننده تعاملی و قابل کشیدن ، کاربران را قادر می سازد تا صفحات را در یک نمایش تقسیم تغییر دهند.
- فعالیت پین کردن: کاربران می توانند محتوا را در یک ظرف بچسبانند و ناوبری را در ظرف از ناوبری در ظرف دیگر جدا کنند.
- DIMMING DIMING FULL-SCREEN: هنگام نمایش یک گفتگو ، برنامه ها می توانند مشخص کنند که آیا کل پنجره کار را کم رنگ می کنند یا فقط ظرفی که گفتگو را باز کرده است.
انبساط
گسترش Pane کاربران را قادر می سازد تا فضای صفحه نمایش اختصاص یافته به این دو فعالیت را در یک طرح پان دوگانه تنظیم کنند.
برای سفارشی کردن ظاهر تقسیم کننده پنجره و تنظیم دامنه Draggable تقسیم کننده ، موارد زیر را انجام دهید:
نمونه ای از
DividerAttributes
ایجاد کنیدویژگی های تقسیم کننده را سفارشی کنید:
color
: رنگ جداکننده صفحه قابل کشیدن.widthDp
: عرض جداکننده صفحه قابل کشیدن. رویWIDTH_SYSTEM_DEFAULT
تنظیم کنید تا سیستم بتواند عرض تقسیم کننده را تعیین کند.دامنه درگ: حداقل درصد صفحه یا صفحه می تواند اشغال کند. می تواند از 0.33 تا 0.66 باشد. به
DRAG_RANGE_SYSTEM_DEFAULT
تنظیم کنید تا سیستم محدوده درگ را تعیین کند.
کاتلین
val splitAttributesBuilder: SplitAttributes.Builder = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) if (WindowSdkExtensions.getInstance().extensionVersion >= 6) { splitAttributesBuilder.setDividerAttributes( DividerAttributes.DraggableDividerAttributes.Builder() .setColor(getColor(context, R.color.divider_color)) .setWidthDp(4) .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT) .build() ) } val splitAttributes: SplitAttributes = splitAttributesBuilder.build()
جاوا
SplitAttributes.Builder splitAttributesBuilder = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT); if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 6) { splitAttributesBuilder.setDividerAttributes( new DividerAttributes.DraggableDividerAttributes.Builder() .setColor(ContextCompat.getColor(context, R.color.divider_color)) .setWidthDp(4) .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT) .build() ); } SplitAttributes splitAttributes = splitAttributesBuilder.build();
فعالیت پین
فعالیت پین کردن کاربران را قادر می سازد تا یکی از ویندوزهای تقسیم شده را پین کنند تا فعالیت در حالی که کاربران در پنجره دیگر حرکت می کنند ، باقی بماند. فعالیت پینکاری یک تجربه چند وظیفه ای پیشرفته را فراهم می کند.
برای فعال کردن فعالیت در برنامه خود ، موارد زیر را انجام دهید:
یک دکمه را به پرونده طرح بندی فعالیتی که می خواهید پین کنید اضافه کنید ، به عنوان مثال ، فعالیت جزئیات یک لیست لیست لیست:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/detailActivity" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" tools:context=".DetailActivity"> <TextView android:id="@+id/textViewItemDetail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="36sp" android:textColor="@color/obsidian" app:layout_constraintBottom_toTopOf="@id/pinButton" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatButton android:id="@+id/pinButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/pin_this_activity" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/textViewItemDetail"/> </androidx.constraintlayout.widget.ConstraintLayout>
در روش
onCreate()
فعالیت ، یک شنونده OnClick را روی دکمه تنظیم کنید:کاتلین
pinButton = findViewById(R.id.pinButton) pinButton.setOnClickListener { val splitAttributes: SplitAttributes = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.66f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build() val pinSplitRule = SplitPinRule.Builder() .setSticky(true) .setDefaultSplitAttributes(splitAttributes) .build() SplitController.getInstance(applicationContext).pinTopActivityStack(taskId, pinSplitRule) }
جاوا
Button pinButton = findViewById(R.id.pinButton); pinButton.setOnClickListener( (view) => { SplitAttributes splitAttributes = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.66f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build(); SplitPinRule pinSplitRule = new SplitPinRule.Builder() .setSticky(true) .setDefaultSplitAttributes(splitAttributes) .build(); SplitController.getInstance(getApplicationContext()).pinTopActivityStack(getTaskId(), pinSplitRule); });
صفحه تمام صفحه
فعالیت ها به طور معمول نمایشگرهای آنها را کم می کنند تا توجه به یک گفتگو را جلب کنند. در فعالیت تعبیه شده ، هر دو صفحه نمایشگر دو قطعه باید کم رنگ باشند ، نه فقط صفحه حاوی فعالیتی که گفتگو را باز می کند ، برای یک تجربه UI یکپارچه.
با WindowManager 1.4 و بالاتر ، کل پنجره برنامه به طور پیش فرض هنگام باز شدن گفتگو کم می شود (به EmbeddingConfiguration.DimAreaBehavior.ON_TASK
مراجعه کنید).
برای کم رنگ فقط ظرف فعالیتی که گفتگو را باز کرده است ، EmbeddingConfiguration.DimAreaBehavior.ON_ACTIVITY_STACK
استفاده کنید.
فعالیت را از یک تقسیم به پنجره کامل استخراج کنید
یک پیکربندی جدید ایجاد کنید که فعالیت جانبی را به طور کامل نشان می دهد ، و سپس فعالیت را با نیتی که به همان نمونه برطرف می شود ، مجدداً راه اندازی کنید.
پشتیبانی تقسیم را در زمان اجرا بررسی کنید
تعبیه فعالیت در Android 12L (API سطح 32) و بالاتر پشتیبانی می شود ، اما در برخی از دستگاه ها که نسخه های قبلی پلت فرم را نیز اجرا می کنند نیز موجود است. برای بررسی در زمان اجرا برای در دسترس بودن ویژگی ، از ویژگی SplitController.splitSupportStatus
یا SplitController.getSplitSupportStatus()
استفاده کنید:
کاتلین
if (SplitController.getInstance(this).splitSupportStatus == SplitController.SplitSupportStatus.SPLIT_AVAILABLE) { // Device supports split activity features. }
جاوا
if (SplitController.getInstance(this).getSplitSupportStatus() == SplitController.SplitSupportStatus.SPLIT_AVAILABLE) { // Device supports split activity features. }
در صورت عدم پشتیبانی از شکاف ، فعالیت ها در بالای پشته فعالیت (به دنبال مدل تعبیه غیر فعال) راه اندازی می شوند.
جلوگیری از نادیده گرفتن سیستم
تولید کنندگان دستگاه های Android (تولید کنندگان تجهیزات اصلی یا OEM) می توانند فعالیت تعبیه شده را به عنوان تابعی از سیستم دستگاه پیاده سازی کنند. این سیستم قوانین تقسیم شده را برای برنامه های چند فعالیت مشخص می کند و بر رفتار پنجره ها برنامه ها غلبه می کند. سیستم غلبه بر برنامه های چند فعالیت را به یک حالت تعبیه شده فعالیت تعریف شده توسط سیستم سوق می دهد.
تعبیه فعالیت سیستم می تواند ارائه برنامه را از طریق چیدمان های چند صفحه ای مانند لیست لیست ، بدون هیچ گونه تغییر در برنامه افزایش دهد. با این حال ، تعبیه فعالیت سیستم همچنین ممکن است باعث ایجاد طرح بندی نادرست برنامه ، اشکالات یا درگیری با فعالیت تعبیه شده توسط برنامه شود.
برنامه شما می تواند با تنظیم یک ویژگی در پرونده مانیفست برنامه ، از تعبیه سیستم جلوگیری یا اجازه دهد: به عنوان مثال:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<property
android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE"
android:value="true|false" />
</application>
</manifest>
نام ملک در شیء JetPack Windowmanager WindowProperties
تعریف شده است. اگر برنامه شما فعالیت تعبیه شده را انجام می دهد ، یا اگر می خواهید در غیر این صورت مانع از اعمال سیستم تعبیه شده در برنامه خود شوید ، مقدار آن را بر روی false
تنظیم کنید. مقدار را به true
تنظیم کنید تا سیستم بتواند فعالیت تعریف شده توسط سیستم را در برنامه خود اعمال کند.
محدودیت ها ، محدودیت ها و احتیاط ها
- فقط برنامه میزبان کار ، که به عنوان صاحب فعالیت ریشه در کار شناخته می شود ، می تواند فعالیت های دیگری را در این کار سازماندهی و جاسازی کند. اگر فعالیت هایی که از تعبیه و تقسیم پشتیبانی می کنند در کار متفاوتی که متعلق به یک برنامه متفاوت است ، انجام شود ، تعبیه و تقسیم برای آن فعالیت ها کار نمی کند.
- فعالیت ها فقط می توانند در یک کار واحد سازماندهی شوند. راه اندازی یک فعالیت در یک کار جدید ، همیشه آن را در یک پنجره جدید گسترده در خارج از هر شکاف موجود قرار می دهد.
- فقط فعالیتهای موجود در همان فرآیند می توانند سازماندهی و تقسیم شوند. پاسخ به تماس
SplitInfo
فقط فعالیتهایی را که متعلق به همان فرآیند است ، گزارش می دهد ، زیرا هیچ راهی برای دانستن فعالیت در فرآیندهای مختلف وجود ندارد. - هر جفت یا قانون فعالیت مفرد فقط برای راه اندازی فعالیتهایی که پس از ثبت قانون اتفاق می افتد اعمال می شود. در حال حاضر هیچ راهی برای به روزرسانی شکاف های موجود یا خصوصیات بصری آنها وجود ندارد.
- پیکربندی فیلتر Split Pair باید با اهداف مورد استفاده در هنگام راه اندازی کامل فعالیت ها مطابقت داشته باشد. تطبیق در جایی اتفاق می افتد که فعالیت جدیدی از فرآیند درخواست آغاز می شود ، بنابراین ممکن است در مورد نام های مؤلفه ای که بعداً در فرآیند سیستم هنگام استفاده از اهداف ضمنی حل می شوند ، آگاهی نداشته باشد. اگر در زمان راه اندازی یک نام مؤلفه مشخص نباشد ، می توان از کارت وحشی به جای آن استفاده کرد ("*/*") و فیلتر می تواند بر اساس عمل قصد انجام شود.
- در حال حاضر هیچ راهی برای جابجایی فعالیت ها بین ظروف یا درون و خارج از شکاف پس از ایجاد وجود ندارد. شکاف ها فقط توسط کتابخانه Windowmanager ایجاد می شوند که فعالیت های جدید با قوانین مطابق با آنها راه اندازی می شود و با پایان یافتن آخرین فعالیت در یک ظرف تقسیم ، شکاف ها از بین می روند.
- فعالیت ها می توانند هنگامی که پیکربندی تغییر می کند ، مجدداً راه اندازی شود ، بنابراین وقتی شکاف ایجاد می شود یا حذف می شود و محدودیت فعالیت ها تغییر می کنند ، فعالیت می تواند از طریق تخریب کامل نمونه قبلی و ایجاد یک مورد جدید انجام شود. در نتیجه ، توسعه دهندگان برنامه باید در مورد مواردی مانند راه اندازی فعالیت های جدید از تماس های چرخه عمر ، مراقب باشند.
- دستگاه ها برای پشتیبانی از تعبیه فعالیت باید رابط افزودنی پنجره را شامل شوند. تقریباً تمام دستگاه های صفحه نمایش بزرگ که Android 12L (سطح API 32) یا بالاتر را اجرا می کنند ، شامل رابط هستند. با این حال ، برخی از دستگاه های صفحه نمایش بزرگ که قادر به انجام چندین فعالیت نیستند ، شامل رابط افزودنی پنجره نیستند. اگر یک دستگاه صفحه نمایش بزرگ از حالت چند پنجره پشتیبانی نمی کند ، ممکن است از تعبیه فعالیت پشتیبانی نکند.
منابع اضافی
- CodeLabs:
- مسیر یادگیری - تعبیه فعالیت
- برنامه نمونه- تعبیه فعالیت