ما اخیراً یک ویژگی جدید به نام Ideas را در Buffer راه اندازی کردیم. با ایدهها، میتوانید بهترین ایدههای خود را ذخیره کنید، آنها را تا زمانی که آماده شوند تغییر دهید و مستقیماً در صف بافر خود قرار دهید. اکنون که Ideas در برنامه های وب و تلفن همراه ما راه اندازی شده است، مدتی فرصت داریم تا برخی از آموخته های توسعه این ویژگی را به اشتراک بگذاریم. در این پست وبلاگ، به نحوه اضافه کردن پشتیبانی از برجسته کردن URL به Ideas Composer در اندروید با استفاده از Jetpack Compose خواهیم پرداخت.
ما در سال 2021 شروع به استفاده از Jetpack Compose در برنامه خود کردیم – از آن به عنوان استاندارد برای ساخت همه ویژگیهای جدید خود استفاده کردیم، در حالی که به تدریج آن را در بخشهای موجود برنامه خود به کار بردیم. ما کل ویژگی Ideas را با استفاده از Jetpack Compose ساختیم – بنابراین در کنار توسعه سریعتر ویژگی و قابلیت پیشبینی بیشتر در وضعیت رابط کاربری خود، فرصتهای زیادی برای بررسی بیشتر Compose و کسب اطلاعات بیشتر در مورد چگونگی دستیابی به الزامات خاص در برنامهمان داشتیم.
در آهنگساز ایدهها، از برجستهسازی پیوند پویا پشتیبانی میکنیم. این بدان معنی است که اگر یک URL را در ناحیه متن تایپ کنید، پیوند برجسته می شود – با ضربه زدن روی این پیوند، یک پاپ آپ “پیوند باز” نشان داده می شود که پس از کلیک کردن، پیوند را در مرورگر راه اندازی می کند.

در این پست وبلاگ، ما بر روی پیادهسازی برجستهسازی پیوند تمرکز میکنیم و اینکه چگونه میتوان به آن در Jetpack Compose با استفاده از TextField
قابل ترکیب
برای آهنگساز Ideas، ما از آن استفاده می کنیم TextField
قابل ترکیب برای پشتیبانی از ورود متن این ترکیب شامل یک آرگومان است، visualTransformation
، که برای اعمال تغییرات بصری در متن وارد شده استفاده می شود.
TextField(
...
visualTransformation = ...
)
این استدلال مستلزم الف VisualTransformation
پیاده سازی که برای اعمال تبدیل بصری به متن وارد شده استفاده می شود. اگر به کد منبع این رابط نگاه کنیم، متوجه یک تابع فیلتر می شویم که محتوای TextField را می گیرد و یک عدد را برمی گرداند. TransformedText
مرجعی که حاوی متن اصلاح شده است.
@Immutable
fun interface VisualTransformation {
fun filter(text: AnnotatedString): TransformedText
}
وقتی نوبت به این متن تغییر یافته میرسد، باید پیادهسازی را ارائه دهیم که یک متن جدید ایجاد میکند AnnotatedString
مرجع با تغییرات اعمال شده ما. این محتوای تغییر یافته سپس در بسته بندی می شود TransformedText
تایپ کنید و به TextField
برای ترکیب
به طوری که بتوانیم تغییراتی را در محتوای خود تعریف و اعمال کنیم TextField
، باید با ایجاد یک پیاده سازی جدید شروع کنیم VisualTransformation
رابطی که برای آن یک کلاس جدید ایجاد خواهیم کرد، UrlTransformation
. این کلاس پیاده سازی می کند VisualTransformation
استدلال، همراه با گرفتن یک آرگومان واحد به شکل الف Color
. ما این آرگومان را تعریف میکنیم تا بتوانیم یک مرجع رنگ تم را برای اعمال در منطق خود ارسال کنیم، زیرا خارج از محدوده قابل ترکیب قرار میگیریم و به تم قابل ترکیب خود دسترسی نخواهیم داشت.
class UrlTransformation(
val color: Color
) : VisualTransformation {
}
با تعریف این کلاس، اکنون باید تابع فیلتر را از the پیاده سازی کنیم VisualTransformation
رابط. در این تابع، ما یک نمونه از را برمی گردانیم TransformedText
class – میتوانیم به کد منبع این کلاس برویم و ببینیم که برای نمونهسازی این کلاس دو ویژگی لازم است.
/**
* The transformed text with offset offset mapping
*/
class TransformedText(
/**
* The transformed text
*/
val text: AnnotatedString,
/**
* The map used for bidirectional offset mapping from original to transformed text.
*/
val offsetMapping: OffsetMapping
)
هر دوی این آرگومانها مورد نیاز هستند، بنابراین هنگام نمونهسازی باید برای هر یک مقداری ارائه کنیم. TransformedText
کلاس
- متن – این نسخه اصلاح شده متنی است که به تابع فیلتر ارائه می شود
- offsetMapping – طبق مستندات، این نقشه ای است که برای نگاشت افست دو طرفه از متن اصلی به متن تبدیل شده استفاده می شود
class UrlTransformation(
val color: Color
) : VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
return TransformedText(
...,
OffsetMapping.Identity
)
}
}
برای offsetMapping
استدلال، ما به سادگی عبور می کنیم OffsetMapping.Identity
مقدار – این مقدار پیش فرض از پیش تعریف شده است که برای OffsetMapping
رابط، برای زمانی استفاده می شود که می تواند برای تبدیل متنی که تعداد کاراکترها را تغییر نمی دهد استفاده شود. وقتی نوبت به آرگومان متن میرسد، باید منطقی بنویسیم که محتوای فعلی را بگیرد، برجستهسازی را اعمال کرده و آن را بهعنوان یک جدید برگرداند. AnnotatedString
مرجع به ما منتقل شود TransformedText
مرجع. برای این منطق، ما یک تابع جدید ایجاد می کنیم، buildAnnotatedStringWithUrlHighlighting
. این به دو آرگومان نیاز دارد – متنی که قرار است برجسته شود، همراه با رنگی که برای برجسته سازی استفاده می شود.
fun buildAnnotatedStringWithUrlHighlighting(
text: String,
color: Color
): AnnotatedString {
}
از این تابع، باید an را برگردانیم AnnotatedString
مرجع، که با استفاده از آن ایجاد خواهیم کرد buildAnnotatedString
. در این تابع، با استفاده از عملیات الحاق برای تنظیم محتوای متنی شروع می کنیم AnnotatedString
.
fun buildAnnotatedStringWithUrlHighlighting(
text: String,
color: Color
): AnnotatedString {
return buildAnnotatedString {
append(text)
}
}
در مرحله بعد، ما باید محتویات رشته خود را برداریم و بر روی URL هایی که وجود دارد، برجسته سازی کنیم. قبل از انجام این کار، باید URL های موجود در رشته را شناسایی کنیم. تشخیص URL ممکن است بسته به مورد استفاده متفاوت باشد، بنابراین برای ساده نگه داشتن موارد، اجازه دهید چند کد نمونه بنویسیم که URL ها را در یک قطعه متن مشخص پیدا می کند. این کد رشته داده شده را می گیرد و URL ها را فیلتر می کند و در نتیجه لیستی از رشته های URL را ارائه می دهد.
text?.split("\\s+".toRegex())?.filter { word ->
Patterns.WEB_URL.matcher(word).matches()
}
اکنون که می دانیم URL ها در رشته چه هستند، باید برجسته سازی را برای آنها اعمال کنیم. این به شکل یک سبک رشته مشروح است که با استفاده از عملیات addStyle اعمال می شود.
fun addStyle(style: SpanStyle, start: Int, end: Int)
هنگام فراخوانی این تابع، باید آن را پاس کنیم SpanStyle
که می خواهیم به همراه شاخص شروع و پایانی که این استایل باید روی آن اعمال شود، اعمال کنیم. ما می خواهیم با محاسبه این شاخص شروع و پایان شروع کنیم – برای ساده نگه داشتن کارها، فرض می کنیم فقط URL های منحصر به فردی در رشته ما وجود دارد.
text?.split("\\s+".toRegex())?.filter { word ->
Patterns.WEB_URL.matcher(word).matches()
}.forEach {
val startIndex = text.indexOf(it)
val endIndex = startIndex + it.length
}
در اینجا ما شاخص شروع را با استفاده از نشان میدهیم indexOf
تابع، که ایندکس شروع URL داده شده را به ما می دهد. سپس از این شاخص شروع و طول URL برای محاسبه شاخص پایان استفاده می کنیم. سپس میتوانیم این مقادیر را به آرگومانهای مربوطه برای the ارسال کنیم addStyle
عملکرد.
text?.split("\\s+".toRegex())?.filter { word ->
Patterns.WEB_URL.matcher(word).matches()
}.forEach {
val startIndex = text.indexOf(it)
val endIndex = startIndex + it.length
addStyle(
start = startIndex,
end = endIndex
)
}
در مرحله بعد، باید آن را ارائه کنیم SpanStyle
که می خواهیم در محدوده شاخص داده شده اعمال شود. در اینجا می خواهیم به سادگی متن را با استفاده از رنگ ارائه شده برجسته کنیم، بنابراین مقدار رنگ را از آرگومان های تابع خود به عنوان آرگومان رنگی ارسال می کنیم. SpanStyle
عملکرد.
text?.split("\\s+".toRegex())?.filter { word ->
Patterns.WEB_URL.matcher(word).matches()
}.forEach {
val startIndex = text.indexOf(it)
val endIndex = startIndex + it.length
addStyle(
style = SpanStyle(
color = color
),
start = startIndex,
end = endIndex
)
}
با این کار، اکنون یک تابع کامل داریم که متن ارائه شده را می گیرد و هر URL را با استفاده از ارائه شده برجسته می کند Color
مرجع.
fun buildAnnotatedStringWithUrlHighlighting(
text: String,
color: Color
): AnnotatedString {
return buildAnnotatedString {
append(text)
text?.split("\\s+".toRegex())?.filter { word ->
Patterns.WEB_URL.matcher(word).matches()
}.forEach {
val startIndex = text.indexOf(it)
val endIndex = startIndex + it.length
addStyle(
style = SpanStyle(
color = color,
textDecoration = TextDecoration.None
),
start = startIndex, end = endIndex
)
}
}
}
پس از آن باید دوباره به درون خودمان برگردیم UrlTransformation
کلاس و پاس کردن نتیجه از buildAnnotatedStringWithUrlHighlighting
فراخوانی تابع برای TransformedText
بحث و جدل.
class UrlTransformation(
val color: Color
) : VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
return TransformedText(
buildAnnotatedStringWithUrlHighlighting(text, color),
OffsetMapping.Identity
)
}
}
حالا که ما UrlTransformation
پیاده سازی کامل است، ما می توانیم این را نمونه سازی کنیم و مرجع را برای آن ارسال کنیم visualTransformation
استدلال از TextField
قابل ترکیب در اینجا ما از رنگ مورد نظر خود استفاده می کنیم MaterialTheme
مرجع، که هنگام برجسته کردن URL ها در ما استفاده می شود TextField
محتوا.
TextField(
...
visualTransformation = UrlTransformation(
MaterialTheme.colors.secondary)
)
با وجود موارد فوق، ما اکنون پشتیبانی از برجسته کردن URL پویا در داخل خود داریم TextField
قابل ترکیب این بدان معناست که اکنون هر زمان که کاربر یک URL را برای یک ایده در آهنگساز وارد می کند، با برجسته کردن آن با استفاده از یک رنگ ثانویه از موضوع خود، آن را به عنوان یک URL شناسایی می کنیم.

در این پست، ما یاد گرفتیم که چگونه می توانیم برجسته سازی پویا URL را در محتویات a اعمال کنیم TextField
قابل ترکیب در پست بعدی، بررسی خواهیم کرد که چگونه هنگامی که یک URL در ناحیه ورودی آهنگساز ضربه زده میشود، پنجره باز کردن پیوند را اضافه میکنیم.