اخبار محصول

ویژگی‌های جدید Jetpack Compose نسخه آگوست 26

۵ دقیقه مطالعه
مشاهده پروفایل نیک بوچر
Nick Butcher مدیر محصول

امروز، نسخه Jetpack Compose که در آگوست 26 منتشر شد، پایدار است! این نسخه، نسخه 1.12 را در سراسر ماژول‌های اصلی Compose ارائه می‌دهد (به نگاشت کامل BOM مراجعه کنید)، APIهای بصری غنی مانند Mesh Gradients و پشتیبانی از Wide Color Gamut (WCG)، ویژگی‌های طرح‌بندی ساختاری مانند نواحی نامگذاری شده در Grid ، ادغام یکپارچه با Credential Manager اندروید و بهبودهای قابل توجه در تست و عملکرد را معرفی می‌کند.

برای به‌روزرسانی پروژه خود به نسخه امروز، نسخه Compose BOM خود را به 2026.08.00 ارتقا دهید:

implementation(platform("androidx.compose:compose-bom:2026.08.00"))

تغییرات اساسی

  • AGP و کامپایل SDK : Compose 1.12 کامپایل SDK را به API 37 به‌روزرسانی می‌کند و حداقل به AGP 9.1.2 نیاز دارد. به عنوان یادآوری، Compose همیشه آخرین کامپایل SDK را هدف قرار می‌دهد. برای اطلاعات بیشتر در مورد این تغییر، اینجا را ببینید.
  • Modifier.onFirstVisible() منسوخ شده است : به Modifier.onVisibilityChanged() مهاجرت کنید، که ردیابی آستانه دید دقیق‌تری را ارائه می‌دهد.

گرافیک

گرادیان‌های مش

کامپوز ۱.۱۲، MeshGradientPainter را معرفی می‌کند تا به شما در ایجاد گرادیان‌های رنگی ارگانیک و چند نقطه‌ای کمک کند.

مشGradient.gif
val rows = 1
val columns = 1

val gradientPainter = remember {
    MeshGradientPainter(rows, columns) {
        // Parameters: row, column, position, color
        setVertex(0, 0, Offset(0f, 0f), Color.Red)     // Top-Left
        setVertex(0, 1, Offset(1f, 0f), Color.Blue)    // Top-Right
        setVertex(1, 0, Offset(0f, 1f), Color.Green)   // Bottom-Left
        setVertex(1, 1, Offset(1f, 1f), Color.Yellow)  // Bottom-Right
    }
}

Box(
    modifier = modifier
        .aspectRatio(16/9f)
        .fillMaxWidth()
        .paint(gradientPainter)
)

برای اطلاعات بیشتر و مثال‌ها، به مستندات مراجعه کنید.

پشتیبانی از طیف رنگی گسترده و HDR

نمایشگرهای مدرن، وفاداری رنگ گسترده‌تر و محدوده دینامیکی بالاتری را ارائه می‌دهند. در Compose 1.12، پشتیبانی کامل از طیف رنگی گسترده (P3) و رندر HDR در گرافیک، رنگ‌آمیزی و سایه‌زن‌های Compose فعال شده است. رنگ‌های تعریف‌شده در فضاهای رنگی غیر sRGB (مانند Display P3) بدون محدودیت رنگ، در رندر پلتفرم حفظ می‌شوند. اگر رنگ‌ها از یک فضای رنگی پشتیبانی‌نشده (مانند CieXyz، CieLab یا Oklab) استفاده کنند، یا به یک فضای رنگی در یک نسخه اندروید پشتیبانی‌نشده (مانند Bt2020Hlg در اندروید ۱۳ و پایین‌تر) متکی باشند، یا اگر برنامه روی اندروید ۹ (API 28) و پایین‌تر اجرا شود، با خیال راحت به sRGB برمی‌گردند.

سایر تغییرات قابل توجه:

  • LayerOutsets به GraphicsLayer و Modifier.graphicsLayer اضافه شد که می‌توانید از آن برای افزایش مرزهای بصری لایه فراتر از اندازه اندازه‌گیری شده آن استفاده کنید. LayerOutsets را اعمال کنید تا از رفتار ضمنی clipToBounds هنگام انتقال لایه به یک بافر خارج از صفحه جلوگیری شود.

سبک‌ها

در کنفرانس Google I/O، ما چشم‌انداز اولیه خود را برای Compose Styles API - روشی یکپارچه و کارآمد برای استایل‌دهی به کامپوننت‌ها - به اشتراک گذاشتیم. از آن زمان، ما به ساخت معماری زیربنایی ادامه داده‌ایم تا ایمنی نوع دقیق و صحت قابل پیش‌بینی را تضمین کنیم و از ساخت سیستم‌های طراحی سفارشی پشتیبانی کنیم.

برای اطمینان از اینکه این لایه بنیادی را به درستی پیاده‌سازی می‌کنیم، API به صورت آزمایشی باقی خواهد ماند و می‌توانید انتظار تغییرات اساسی را داشته باشید.

بهینه‌سازی‌های زمان اجرا

اضافه بار عوارض جانبی کلیددار

SideEffect اکنون از آرگومان‌های کلید پشتیبانی می‌کند که به شما امکان می‌دهد هر زمان که کلیدهای خاصی تغییر می‌کنند، عوارض جانبی یک‌باره را فعال کنید. این می‌تواند منجر به عملکرد بهتری در مقایسه با استفاده از LaunchedEffect یا DisposableEffect شود، زمانی که به بلوک coroutine یا dispose نیاز ندارید. SideEffect تا 90٪ سریع‌تر از LaunchedEffect و حدود 20٪ سریع‌تر از DisposableEffect است. توجه داشته باشید که SideEffect اثر خود را قبل از DisposableEffect و LaunchedEffect اجرا می‌کند، بنابراین در هنگام انتقال جلوه‌های موجود به این API، به خصوص برای LaunchedEffects که برای شروع پس از تکمیل فریم فعلی به اعزام شدن متکی هستند، احتیاط کنید.

@Composable
fun AnalyticsTracker(userId: String, screenName: String) {
    SideEffect(key1 = userId, key2 = screenName) {
        analytics.logScreenView(userId, screenName)
    }
}

انیمیشن

انتقال‌های دو مرحله‌ای تعاملی

  • ترکیب‌های جدید : DeferredAnimatedContent و DeferredAnimatedVisibility امکان ایجاد گذارهای دو مرحله‌ای لذت‌بخش را فراهم می‌کنند، مثلاً برای ردیابی حرکات پیش‌بینی‌کننده‌ی بازگشت.
  • کنترل دستی انیمیشن : در طول فاز به تعویق افتاده‌ی یک گذار، ویژگی‌های انیمیشن (مانند مقیاس یا افست) اکنون می‌توانند به صورت دستی و در لحظه دستکاری شوند (مثلاً ردیابی یک حرکت کشیدن انگشت).
  • انتقال یکپارچه : به محض پایان فاز معوق، موتور انتقال، کنترل را به دست می‌گیرد و یک انتقال یکپارچه، شامل انتقال سرعت، به انتقال خودکار انجام می‌دهد.
  • پشتیبانی از عنصر مشترک : یک پرچم جدید permitTransformDuringDeferredTransition در SharedContentConfig کنترل می‌کند که آیا عناصر مشترک در طول مرحله انتقال به تعویق افتاده، به صورت بصری همراه با کانتینرهای والد خود تغییر شکل می‌دهند یا خیر.
val state = remember { DeferredTransitionState(initialScreen) }
val transition = rememberDeferredTransition(state)

if (predictiveBackInProgress) {
    state.defer(targetScreen)
} else {
    state.animateTo(targetScreen)
}

transition.DeferredAnimatedContent(
    targetState = targetScreen,
    mutableTransformSpec = {
       MutableContentTransform {
           // Manually manipulate properties during the deferred phase
           initialContentTransform { scale = swipeProgress }
       }
    }
) { screen ->
    ScreenContent(screen)
}

در زیر دو نمونه از موارد استفاده که در آنها یک انیمیشن مبتنی بر ژست به یک انیمیشن فعال شده (triggered animation) واگذار می‌شود، آورده شده است:

کارت‌های رنگی.gif

ادغام متن، ورودی و پلتفرم

قالب‌بندی متن قابل ویرایش

APIهای جدید، قالب‌بندی متن غنی را برای متن قابل ویرایش در BasicTextField ارائه می‌دهند. اکنون می‌توانید قالب‌بندی درون‌خطی کاراکتر و پاراگراف را با استفاده از SpanStyle و ParagraphStyle از طریق متد جدید addStyle() در داخل یک محدوده TextFieldBuffer (مانند داخل textFieldState.edit { ... } یا یک InputTransformation ) به صورت برنامه‌نویسی اعمال و دستکاری کنید. علاوه بر این، TextFieldBuffer APIهای getSpanStyles() و getParagraphStyles() را ارائه می‌دهد که اشیاء TrackedRange برمی‌گردانند و به شما امکان می‌دهند سبک‌های اعمال شده را بخوانید، به‌روزرسانی یا حذف کنید. برای تکمیل ایجاد قالب‌بندی، TextFieldState اکنون یک ویژگی textStyles فقط خواندنی را برای پرس‌وجو از سبک‌های فعال در سراسر محدوده‌ها ارائه می‌دهد، در حالی که TextFieldBuffer originalTextStyles برای بررسی وضعیت قالب‌بندی قبل از ویرایش ارائه می‌دهد. قالب‌بندی متن و حاشیه‌نویسی‌های سفارشی در طول تغییرات پیکربندی حفظ می‌شوند.

val state = rememberTextFieldState("Formatted text in Compose 1.12")

// Apply bold and color styles to a range of text
state.edit {
    addStyle(
        SpanStyle(fontWeight = FontWeight.Bold, color = Color.Blue),
        start = 0,
        end = 9
    )
}

// Query active styles from TextFieldState
val currentStyles = state.textStyles

انتخاب متن

یک رابط برنامه‌نویسی کاربردی جدید SelectionState کنترل برنامه‌نویسی و قابلیت مشاهده بر انتخاب متن درون SelectionContainer را فراهم می‌کند. انتقال یک شیء SelectionState از طریق rememberSelectionState() و ارسال آن به SelectionContainer selectedTexts به عنوان یک لیست واکنشی از AnnotatedStrings در معرض نمایش قرار می‌دهد و متدهایی مانند selectAll() ، clear() ، select(TextRange) و extendSelectionByWord() را ارائه می‌دهد.

علاوه بر این، از getSelectableTexts() برای بازیابی تمام آیتم‌های متنی قابل انتخاب به ترتیب طرح‌بندی استفاده کنید و متن را در سراسر composables در SelectionContainer با استفاده از یک محدوده سراسری انتخاب کنید.

@Composable
fun ProgrammaticSelectionExample() {
    val selectionState = rememberSelectionState()

    Column {
        Button(
            onClick = { selectionState.selectAll() },
            modifier = Modifier.disableSelectionClearOnTap()
        ) {
            Text("Select All")
        }

        SelectionContainer(state = selectionState) {
            Text("Text content to be selected programmatically.")
        }
    }
}

یکپارچه‌سازی مدیریت اعتبارنامه

فیلدهای متنی Compose اکنون به صورت بومی با Credential Manager اندروید (API 34+) از طریق چارچوب Autofill ادغام می‌شوند (API 34 زیر توسط androidx.credentials library مدیریت می‌شود). با پیوست کردن ویژگی جدید credentialRequest semantics به CredentialRequestData ، ورودی‌های متنی می‌توانند کلیدهای عبور، اعتبارنامه‌های ذخیره شده یا درخواست‌های ورود را مستقیماً در جریان ورودی کاربر فراخوانی کنند.

@Composable
fun LoginField(textFieldState: TextFieldState) {
    val credentialData = remember {
        CredentialRequestData(
            // Specify Credential Manager request options
        )
    }

    BasicTextField(
        state = textFieldState,
        modifier = Modifier.semantics {
            credentialRequest = credentialData
        }
    )
}

سایر تغییرات قابل توجه:

  • پشتیبانی از تنظیمات تغییر فونت در فونت‌های قابل دانلود .
  • فعال کردن پیمایش خودکار هنگام کشیدن متن انتخاب شده به فراتر از نمای دید در SelectionContainer .
  • پشتیبانی از صداهای تعامل خودکار (کلیک‌ها و ناوبری فوکوس) به کامپوننت‌های Compose اضافه شده است، به همراه یک SoundEffectOnInteraction جدید که قابلیت ترکیب دارد و امکان انصراف را فراهم می‌کند. توجه داشته باشید که در نتیجه این تغییر، اکنون باید شنونده‌های کلیک معنایی از نخ اصلی فراخوانی شوند که ممکن است بر تعداد کمی از موارد آزمایشی تأثیر بگذارد.
  • KeyboardType اکنون شامل Date ، Time ، DateTime و SignedDecimal می‌شود.
  • BasicSecureTextField اکنون به طور پیش‌فرض TextObfuscationMode.System استفاده می‌کند، در حالی که RevealLastTyped به عنوان یک جایگزین مطلق عمل می‌کند.

بهبودهای طرح‌بندی

نواحی نامگذاری شده در طرح شبکه‌ای

ساخت طرح‌بندی‌های پیچیده دوبعدی اکنون با استفاده از ناحیه‌های نامگذاری‌شده در کامپوننت @Experimental Grid آسان‌تر شده است. به جای مدیریت شاخص‌های عددی ستون و ردیف در بین آیتم‌ها، می‌توانید ناحیه‌های معنایی را در GridConfigurationScope خود تعریف کنید و ترکیب‌پذیرها را بر اساس نام ناحیه قرار دهید.

@OptIn(ExperimentalGridApi::class)
@Composable
fun DashboardLayout() {
    Grid(
        config = {
            area("header", row = 0, column = 0, rowSpan = 1, columnSpan = 2)
            area("sidebar", row = 1, column = 0)
            area("content", row = 1, column = 1)
            gap(16.dp)
        }
    ) {
        HeaderSection(modifier = Modifier.gridItem(areaId = "header"))
        NavigationSidebar(modifier = Modifier.gridItem(areaId = "sidebar"))
        MainContentView(modifier = Modifier.gridItem(areaId = "content"))
    }
}

برای اطلاعات بیشتر، به مستندات مراجعه کنید.

عملکرد

مانند هر نسخه، ما همچنان بر روی عملکرد Compose سرمایه‌گذاری می‌کنیم تا اطمینان حاصل کنیم که این چارچوب به شما در ساخت برنامه‌های زیبا و کارآمد کمک می‌کند. در این نسخه، ما بر بهبود عملکرد راه‌اندازی تمرکز کرده‌ایم و اکنون شاهد زمان نمایش اولیه (زمانی که طول می‌کشد تا یک برنامه اولین فریم خود را تولید کند) هستیم که با Views در معیارهای ما قابل مقایسه است.

timetoinitialdisplay@2x _v2.png

ارتقاء تست و ابزار

همگام‌سازی تست

کامپوز ۱.۱۲ رابط‌های برنامه‌نویسی تست جدیدی را معرفی می‌کند که برای کاهش زمان اجرای تست و از بین بردن ناهمواری‌ها در طول نمونه‌برداری حالت طراحی شده‌اند:

  • hasPendingWork : به صورت غیرفعال بررسی می‌کند که آیا رابط کاربری کار در حال انتظاری دارد یا خیر، بدون اینکه ساعت را جلو ببرد، که برای حلقه‌های انیمیشن دستی ایده‌آل است.
  • runWithoutImplicitWait : هنگام عبور از فریم‌های ساعت دستی (مثلاً تست‌های انیمیشن)، همگام‌سازی ضمنی را به‌طور موقت غیرفعال می‌کند.
@Test
fun testAnimationStateFast() {

composeTestRule.mainClock.autoAdvance = false
    
    while (composeTestRule.hasPendingWork()) {
        composeTestRule.mainClock.advanceTimeByFrame()
        composeTestRule.waitForIdle()
        
        composeTestRule.runOnUiThread {
            composeTestRule.runWithoutImplicitWait {
                // This is most effective when querying multiple nodes in a single frame. 
                // It prevents the redundant synchronization overhead that would 
                // otherwise occur on every individual query.
                val box1 = composeTestRule.onNodeWithTag("Box1").fetchSemanticsNode()
                val box2 = composeTestRule.onNodeWithTag("Box2").fetchSemanticsNode()
                
                assertThat(box1.boundsInRoot.right).isAtMost(box2.boundsInRoot.left)
            }
        }
    }
}

سایر تغییرات قابل توجه:

  • API captureToImage اکنون به شما امکان می‌دهد یک پنجره یا کادر محاوره‌ای را به همراه لنگر آن در یک بیت‌مپ واحد ضبط کنید.
  • onRootWithViewInteraction به دامنه جستجوهای معنایی Compose برای Viewهای خاص اندروید اضافه شد. این امر آزمایش رابط‌های کاربری ترکیبی، مانند RecyclerViews ، را بدون نیاز به تگ‌های تست منحصر به فرد در کد عملیاتی، ساده می‌کند.
  • حاشیه‌نویسی‌های @PreviewWrapper اکنون می‌توانند روی کلاس‌های سفارشی @MultiPreview اعمال شوند و امکان تنظیمات پیش‌نمایش قابل استفاده مجدد (مانند تم‌های سفارشی) را در چندین کامپوننت فراهم کنند.

آهنگسازی مبارک!

Compose 1.12 با گرادیان‌های مش، پشتیبانی از طیف رنگی گسترده، فونت‌های متغیر قابل دانلود، ادغام Credential Manager و ابزارهای تست سریع‌تر، توسعه برنامه را آسان‌تر و رساتر از همیشه می‌کند. مثل همیشه، ما برای نظرات شما ارزش قائلیم، بنابراین لطفاً نظرات خود را در مورد این تغییرات یا آنچه که می‌خواهید در ادامه در ردیاب مشکلات ما ببینید، به اشتراک بگذارید. از نوشتن لذت ببرید!

نوشته شده توسط:
ادامه مطلب