Jetpack Compose
للألعاب وتحريك الأشكال
وجهات كريم
wajahatkarim.com
WajahatKarim
🔥 خبير من جوجل في مجال الأندرويد (GDE) .
📱 مبرمج أندرويد 💻 مشارك في العناصر مفتوحة المصدر
📝 كاتب تقني 🎤 متحدث في المؤتمرات
compose_version = '1.0.0-beta05'
تم التحديث لنسخة
Jetpack Compose
مجموعة أدوات حديثة لواجهة المستخدم لتبسيط وتسريع برمجة شاشات المستخدم على بإستخدام كود أقل وأدوات قوية Android نظام Kotlin ولغة
Jetpack Compose تم عمله بـ
Jetpack Compose تحريك الأشكال في
animateContentSize() معدل
AnimatedVisibility Composable
animate*AsState() تحريك عنصر واحد بإستخدام
Animatable تكرار الحركة بإستخدام
أستخدام تحويل الأشكال لعمل تحريك مثالي
Jetpack Compose تحريك الأشكال في
animateContentSize() معدل
AnimatedVisibility Composable
animate*AsState() تحريك عنصر واحد بإستخدام
Animatable تكرار الحركة بإستخدام
أستخدام تحويل الأشكال لعمل تحريك مثالي
animateContentSize() معدل
animateContentSize() معدل
@Composable
fun ExpandableText() {
val shortText = "Click me"
val longText = "Very long text passage that spans
\nacross multiple lines, paragraphs
\nand pages"
var short by remember { mutableStateOf(true) }
Box(
modifier = Modifier
.background(
Color.Blue,
RoundedCornerShape(15.dp)
)
.clickable { short = !short }
.padding(20.dp)
.wrapContentSize()
.animateContentSize()
) {
Text(
if (short) {
shortText
} else {
longText
},
style = TextStyle(color = Color.White)
)
}
}
@Composable
fun PortraitModeImage() {
var portraitMode by remember { mutableStateOf(true) }
Box(
Modifier.clickable { portraitMode = !portraitMode }
.sizeIn(maxWidth = 300.dp, maxHeight = 300.dp)
.background(
if (portraitMode) Color.Yellow else Color.Green)
.animateContentSize(
animSpec = tween(500, easing = LinearEasing),
endListener = { startSize, endSize ->
Log.d("Compose", "$startSize -> $endSize")
}
)
.aspectRatio(if (portraitMode) 3 / 4f else 16 / 9f)
) {
Text(
if (portraitMode) {
"3 : 4"
} else {
"16 : 9"
},
style = TextStyle(color = Color.Black)
)
}
}
animateContentSize() معدل
Jetpack Compose تحريك الأشكال في
animateContentSize() معدل
AnimatedVisibility Composable
animate*AsState() تحريك عنصر واحد بإستخدام
Animatable تكرار الحركة بإستخدام
أستخدام تحويل الأشكال لعمل تحريك مثالي
AnimatedVisibility Composable
AnimatedVisbility Composable
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun VisibilityAnimationFAB() {
var expanded by remember { mutableStateOf(true) }
FloatingActionButton(
onClick = { expanded = !expanded },
) {
Row(Modifier.padding(start = 16.dp, end = 16.dp)) {
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = "Favorite Icon",
Modifier.align(Alignment.CenterVertically)
)
AnimatedVisibility(
expanded,
modifier = Modifier.align(Alignment.CenterVertically)
) {
Text(modifier = Modifier.padding(start = 8.dp), text = "Like")
}
}
}
}
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun VisibilityAnimationFAB() {
var expanded by remember { mutableStateOf(true) }
FloatingActionButton(
onClick = { expanded = !expanded },
) {
Row(Modifier.padding(start = 16.dp, end = 16.dp)) {
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = "Favorite Icon",
Modifier.align(Alignment.CenterVertically)
)
AnimatedVisibility(
expanded,
modifier = Modifier.align(Alignment.CenterVertically),
enter = slideInHorizontally(
initialOffsetX = { 300 },
animSpec = tween(durationMillis = 2000)
),
exit = slideOutVertically(
targetOffsetY = { 100 },
animSpec = tween(durationMillis = 2000)
)
) {
Text(text = "Like")
}
}
}
}
Default
Enter
Enter + Exit
AnimatedVisbility Composable
cs.android.com
LazyColumn في AnimatedVisibility
Composables في عدة AnimatedVisibility
AnimatedVisbility Composable
Jetpack Compose تحريك الأشكال في
animateContentSize() معدل
AnimatedVisibility Composable
animate*AsState() تحريك عنصر واحد بإستخدام
Animatable تكرار الحركة بإستخدام
أستخدام تحويل الأشكال لعمل تحريك مثالي
animate*AsState() تحريك عنصر واحد بإستخدام
animate*AsState()
لتحريك قيمة عنصر واحد fire-and-forget وظائف
تم إلغاءه animate() سابقا
للألوان animatedColorAsState()
DP لقيم الأحجام animatedDpAsState()
... والمزيد
@Composable
fun ScaleAndColorAnimation() {
val enabled = remember { mutableStateOf(true) }
val color: Color by animateColorAsState(
if (enabled.value) Color.Blue else Colors.green)
val height: Dp by animateDpAsState(if (enabled.value) 40.dp else 60.dp)
val width: Dp by animateDpAsState(if (enabled.value) 150.dp else 300.dp)
Button(
onClick = { enabled.value = !enabled.value },
colors = ButtonDefaults.buttonColors(backgroundColor = color),
modifier = Modifier
.padding(16.dp)
.preferredHeight(height)
.preferredWidth(width),
) {
Text("Scale & Color")
}
}
1 - animate*AsState()
2 - animate*AsState()
@Composable
fun GenderSelectAnimation() {
val female = remember { mutableStateOf(true) }
Row(horizontalArrangement = Arrangement.Center,
modifier = Modifier.padding(8.dp).fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(R.drawable.male),
contentDescription = "Male Image",
contentScale = ContentScale.Crop,
modifier = Modifier
.preferredSize(animateDpAsState(if (female.value) 100.dp else 250.dp).value)
.border(width = animateDpAsState(if (female.value) 0.dp else 4.dp).value,
color = animateColorAsState(if (female.value) Color.Transparent else Color.Red).value)
.padding(8.dp)
.clickable { female.value = !female.value }
)
Image(
painter = painterResource(R.drawable.female),
contentDescription = "Female Image",
contentScale = ContentScale.Crop,
modifier = Modifier
// ...
// Like previous image
)
}
}
animate*AsState() أمثلة على
github.com/Gurupreet/ComposeCookBook
Jetpack Compose تحريك الأشكال في
animateContentSize() معدل
AnimatedVisibility Composable
animate*AsState() تحريك عنصر واحد بإستخدام
Animatable تكرار الحركة بإستخدام
أستخدام تحويل الأشكال لعمل تحريك مثالي
Animatable تكرار الحركة بإستخدام
Animatable تكرار الحركة بإستخدام
@Composable
fun HeartBeatDemo() {
val animScale = remember { Animatable(initialValue = 1f) }
val animColor = remember { Animatable(initialValue = Color.Red) }
LaunchedEffect(animScale) {
animScale.animateTo(
targetValue = 2f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 300, delayMillis = 1000),
repeatMode = RepeatMode.Reverse
)
)
}
LaunchedEffect(animColor) {
animColor.animateTo(
targetValue = Color.Blue,
animationSpec = repeatable(iterations = 2,
animation = tween(durationMillis = 300, delayMillis = 1000),
repeatMode = RepeatMode.Reverse
)
)
}
Image(imageVector = Icons.Default.Favorite,
contentDescription = "Favourite Icon",
modifier = Modifier.padding(10.dp).size((40*animScale.value).dp),
colorFilter = ColorFilter.tint(animColor.value)
)
}
للسماح لك برسم أي شكل عليه Spacer()
@Composable
fun Canvas
(
modifier: Modifier,
onDraw: DrawScope.() -> Unit
) = Spacer(modifier.drawBehind(onDraw))
Compose Canvas 101
drawing API - DrawScope
drawRect()
drawOval()
drawLine()
drawImage()
drawRoundRect()
drawCircle()
drawArc()
drawPath()
fun DrawScope.drawMyShape() { }
Compose Canvas 101
Compose Canvas 101
Canvas مثال شكل معدل بإستخدام
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
color = Color.Red,
radius = 300f
)
drawCircle(
color = Color.Green,
radius = 200f
)
drawCircle(
color = Color.Blue,
radius = 100f
)
}
Canvas بإستخدام Animatable
@Composable
fun MovingSquare() {
val animPosX = remember { Animatable(initialValue = 0f) }
LaunchedEffect(animPosX) {
animPosX.animateTo(
targetValue = 500f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 1000)
)
)
}
Canvas(modifier = Modifier.preferredSize(100.dp), onDraw = {
withTransform({
translate(left = animPosX.value)
}) {
drawRect(color = Color.Red)
}
})
}
مثال بسيط في تحريك مربع
Canvas أمثلة أكثر على
يعتمد بالكامل على الرياضيات والرسم
github.com/wajahatkarim3/DinoCompose
github.com/alexjlockwood/bees-and-bombs-compose/
Jetpack Compose تحريك الأشكال في
animateContentSize() معدل
AnimatedVisibility Composable
animate*AsState() تحريك عنصر واحد بإستخدام
Animatable تكرار الحركة بإستخدام
أستخدام تحويل الأشكال لعمل تحريك مثالي
أستخدام تحويل الأشكال لعمل تحريك مثالي
class DemoActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
DemoTheme {
Scaffold(
topBar = {
TopAppBar( /* App Bar */ )
},
floatingActionButton = {
ExplodingFabButton()
},
bodyContent = {
// Content Composables
}
}
}
}
}
تحويل الأشكال - 1
enum class FabSizeState {
NORMAL, EXPLODED
}
@Composable
fun ExplodingFabButton() {
var fabSizeState by remember { mutableStateOf(FabSizeState.NORMAL) }
val fabTransition: Transition<FabSizeState> = updateTransition(fabSizeState)
val fabSize: Float by fabTransition.animateFloat() { state ->
when (state) {
FabSizeState.NORMAL -> 80f
FabSizeState.EXPLODED -> 5000f
}
}
val fabColor: Color by fabTransition.animateColor() { state ->
when (state) {
FabSizeState.NORMAL -> secondaryColor
FabSizeState.EXPLODED -> primaryColor
}
}
}
تحويل الأشكال - 2
@Composable
fun ExplodingFabButton() {
var fabSizeState by remember { mutableStateOf(FabSizeState.NORMAL) }
val fabTransition: Transition<FabSizeState> = updateTransition(fabSizeState)
val fabSize: Float by fabTransition.animateFloat() { /* from previous slide */ }
val fabColor: Color by fabTransition.animateColor() { /* from previous slide */ }
FloatingActionButton(
onClick = {
fabSizeState = if (fabSizeState == FabSizeState.NORMAL)
FabSizeState.EXPLODED
else FabSizeState.NORMAL
},
modifier = Modifier.size(fabSize.dp),
backgroundColor = fabColor
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "Add"
)
}
}
تحويل الأشكال - 3
val fabSize: Float by fabTransition.animateFloat(
transitionSpec = {
when {
FabSizeState.NORMAL isTransitioningTo FabSizeState.EXPLODED -> {
keyframes {
durationMillis = 1000
80f at 0
35f at 200
5000f at 1000
}
}
FabSizeState.EXPLODED isTransitioningTo FabSizeState.NORMAL -> {
tween(durationMillis = 1000, easing = FastOutSlowInEasing)
}
else -> snap()
}
}
) { state ->
when (state) {
FabSizeState.NORMAL -> 80f
FabSizeState.EXPLODED -> 5000f
}
}
تحويل الأشكال - 4
تحويل الأشكال - 5
تحويل الأشكال - أمثلة
https://joebirch.co/
https://www.raywenderlich.com/13282144-jetpack-compose-animations-tutorial-getting-started
معاين التحريك
ماذا أختار لتحريك العناصر؟
https://developer.android.com/jetpack/compose/animation
المصادر
Alex Lockwood
https://github.com/alexjlockwood/bees-and-bombs-compose
https://github.com/alexjlockwood/android-2048-compose
Joe Birch
https://joebirch.co/exploring-jetpack-compose/
Gurupreet Singh
https://github.com/Gurupreet/ComposeCookBook
Leland Richardson
https://www.twitch.tv/intelligibabble
مصادر جوجل الرسمية
https://developer.android.com/courses/pathways/compose
Vinay Gaba
https://github.com/vinaygaba/Learn-Jetpack-Compose-By-Example
شاكر لحضوركم اليوم
الكود بالمحاضرة مرفوع على
https://github.com/wajahatkarim3/droidcon2020
WajahatKarim
wajahatkarim.com/subscribe
wajahatkarim.com
Jetpack Compose for Games & Animations
By Shady Yehia Selim
Jetpack Compose for Games & Animations
In this talk, we will see how to develop various animations in Jetpack Compose
- 857