{"id":2666,"date":"2025-11-07T11:20:29","date_gmt":"2025-11-07T02:20:29","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=2666"},"modified":"2025-11-07T11:36:35","modified_gmt":"2025-11-07T02:36:35","slug":"compose-insert-image-state-management","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2025\/11\/07\/compose-insert-image-state-management\/","title":{"rendered":"[Compose]\uc774\ubbf8\uc9c0 \ub123\uae30,\uc0c1\ud0dc\uad00\ub9ac \/ Insert image, state management"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb \uc0c1\ud0dc\uad00\ub9ac\ub97c \ud1b5\ud574\uc11c \ubcc4 \ubaa8\uc591\uc744 \ub204\ub974\uba74 \uc544\uc774\ucf58 \ubaa8\uc591\uc774 \ubc14\ub01d\ub2c8\ub2e4.<br>When you click on the star shape through status management, the icon shape changes.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \ub85c\uceec \uc774\ubbf8\uc9c0\uc640 \ub124\ud2b8\uc6cc\ud06c \uc774\ubbf8\uc9c0\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4.<br>Use local and network images.<\/p>\n\n\n\n<p><strong>1.\uc778\ud130\ub137 \uc0ac\uc6a9\uad8c\ud55c \ucd94\uac00 \/ Add Internet access permission<\/strong><\/p>\n\n\n\n<p>\u2714\ufe0fAndroidManifest.xml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?xml version=\"1.0\" encoding=\"utf-8\"?>\n&lt;manifest xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\n    xmlns:tools=\"http:\/\/schemas.android.com\/tools\">\n    &lt;!-- \uc778\ud130\ub137 \uc0ac\uc6a9\uad8c\ud55c \ucd94\uac00 \/ Add Internet access permission -->\n    &lt;uses-permission android:name=\"android.permission.INTERNET\" \/>\n    &lt;application\n        android:allowBackup=\"true\"\n        android:dataExtractionRules=\"@xml\/data_extraction_rules\"\n        android:fullBackupContent=\"@xml\/backup_rules\"\n        android:icon=\"@mipmap\/ic_launcher\"\n        android:label=\"@string\/app_name\"\n        android:roundIcon=\"@mipmap\/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style\/Theme.ImageState\">\n        &lt;activity\n            android:name=\".MainActivity\"\n            android:exported=\"true\"\n            android:label=\"@string\/app_name\"\n            android:theme=\"@style\/Theme.ImageState\">\n            &lt;intent-filter>\n                &lt;action android:name=\"android.intent.action.MAIN\" \/>\n\n                &lt;category android:name=\"android.intent.category.LAUNCHER\" \/>\n            &lt;\/intent-filter>\n        &lt;\/activity>\n    &lt;\/application>\n\n&lt;\/manifest><\/code><\/pre>\n\n\n\n<p><strong>2.\ub77c\uc774\ube0c\ub7ec\ub9ac \ucd94\uac00 \/ Add library<\/strong><\/p>\n\n\n\n<p>\u2714\ufe0fbuild.gradle.kts<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dependencies {\n    implementation(libs.androidx.core.ktx)\n    implementation(libs.androidx.lifecycle.runtime.ktx)\n    implementation(libs.androidx.activity.compose)\n    implementation(platform(libs.androidx.compose.bom))\n    implementation(libs.androidx.compose.ui)\n    implementation(libs.androidx.compose.ui.graphics)\n    implementation(libs.androidx.compose.ui.tooling.preview)\n    implementation(libs.androidx.compose.material3)\n    testImplementation(libs.junit)\n    androidTestImplementation(libs.androidx.junit)\n    androidTestImplementation(libs.androidx.espresso.core)\n    androidTestImplementation(platform(libs.androidx.compose.bom))\n    androidTestImplementation(libs.androidx.compose.ui.test.junit4)\n    debugImplementation(libs.androidx.compose.ui.tooling)\n    debugImplementation(libs.androidx.compose.ui.test.manifest)\n\n<strong>    \/\/ Coil Compose \ud1b5\ud569 \ub77c\uc774\ube0c\ub7ec\ub9ac \ucd94\uac00(\uc778\ud130\ub137 \uc774\ubbf8\uc9c0 \ubd88\ub7ec\uc624\uae30)\n    \/\/ Add Coil Compose integration library (loading internet images)\n    implementation(\"io.coil-kt:coil-compose:2.6.0\")\n    \/\/ \uc544\uc774\ucf58 \uc0ac\uc6a9 \/ Use icons\n    implementation(\"androidx.compose.material:material-icons-extended\")<\/strong>\n}<\/code><\/pre>\n\n\n\n<p><strong>3.\ub85c\uceec \uc774\ubbf8\uc9c0 \ub123\uae30 \/ Insert local image<\/strong><\/p>\n\n\n\n<p>\u2714\ufe0f res\/drawble\/cat.jpg<\/p>\n\n\n\n<p>&#8212; \uc548\ub4dc\ub85c\uc774\ub4dc\uc2a4\ud29c\ub514\uc624\uc758 \ud504\ub85c\uc81d\ud2b8 \ucc3d\uc5d0 \uc774\ubbf8\uc9c0\ub97c \ub04c\uc5b4\ub2e4 \ub193\uc73c\uba74 \ub429\ub2c8\ub2e4.<br>Just drag and drop the image into the project window in Android Studio.<\/p>\n\n\n\n<p><strong>4.\uc18c\uc2a4\ucf54\ub4dc \/ Source Code<\/strong><br>\u2714\ufe0f MainActivity.kts<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.freelifemakers.imagestate\n\nimport android.os.Bundle\nimport androidx.activity.ComponentActivity\nimport androidx.activity.compose.setContent\nimport androidx.activity.enableEdgeToEdge\nimport androidx.compose.foundation.Image\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.filled.Add\nimport androidx.compose.material.icons.filled.Done\nimport androidx.compose.material.icons.filled.Favorite\nimport androidx.compose.material.icons.filled.FavoriteBorder\nimport androidx.compose.material.icons.filled.Star\nimport androidx.compose.material.icons.filled.StarBorder\nimport androidx.compose.material3.Card\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.saveable.rememberSaveable\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.layout.ContentScale\nimport androidx.compose.ui.res.painterResource\nimport androidx.compose.ui.text.style.TextAlign\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\nimport coil.compose.AsyncImage\nimport com.freelifemakers.imagestate.ui.theme.ImageStateTheme\n\n\n\n\/\/ \ub124\ud2b8\uc6cc\ud06c \uc774\ubbf8\uc9c0 URL \/ Network Image URL\nconst val DummyImageUrl = \"https:\/\/picsum.photos\/300\/300\"\n\nclass MainActivity : ComponentActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        enableEdgeToEdge()\n        setContent {\n            ImageStateTheme {\n                MainAppScreen() \/\/ \uc571 \uc2e4\ud589 \/ Run App\n            }\n        }\n    }\n}\n\n\n\/\/ \uba54\uc778\uc2a4\ud06c\ub9b0 \/ Main Screen\n@Composable\nfun MainAppScreen() {\n    Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->\n        \/\/ innerPadding\uc744 \uc801\uc6a9\ud558\uc5ec \uc548\uc804 \uc601\uc5ed\uc744 \ud655\ubcf4\ud569\ub2c8\ub2e4.\n        Column(modifier = Modifier.padding(innerPadding)) {\n            ImageLoadingExample() \/\/&lt;-- ImageWithToggleIcon\n        }\n    }\n}\n\n\/\/ \uc774\ubbf8\uc9c0 \ubd88\ub7ec\uc624\uae30,\uc0c1\ud0dc\uad00\ub9ac,\ud074\ub9ad\uc2dc \uc544\uc774\ucf58 \uc804\ud658\n\/\/ Image loading, state management, icon switching on click\n@Composable\nfun ImageWithToggleIcon(\n    imageContent: @Composable () -> Unit,\n    modifier: Modifier = Modifier\n) {\n    \/\/ \uc0c1\ud0dc \uad00\ub9ac rememberSaveable, mutableStateOf\ub97c \uc0ac\uc6a9\n    \/\/ \uadf8\ub0e5 remember\ub97c \uc0ac\uc6a9 \ud560 \uacbd\uc6b0 \ubaa8\ubc14\uc77c \ud3f0 \ud68c\uc804\uc2dc \ucd08\uae30\ud654 \ub428.\n    \/\/ Use rememberSaveable and mutableStateOf for state management.\n    \/\/ If you just use remember, it will be initialized when the phone is rotated.\n    var isFavorite by rememberSaveable { mutableStateOf(false) }\n\n    \/\/ Box\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc774\ubbf8\uc9c0\uc640 \uc544\uc774\ucf58\uc744 \uacb9\uccd0\uc11c \ubc30\uce58\n    \/\/ Use Box to place images and icons in an overlapping manner\n    Box(\n        modifier = modifier\n            .size(150.dp)\n    ) {\n        \/\/ \uc774\ubbf8\uc9c0 \ubd88\ub7ec\uc624\uae30 \ucef4\ud3ec\uc988(AsyncImage \ub610\ub294 Local Image)\n        \/\/ Load image compose (AsyncImage or Local Image)\n        imageContent()\n\n        \/\/ \ud074\ub9ad \uac00\ub2a5\ud55c \uc544\uc774\ucf58 \/ clickable icon\n        Icon(\n            imageVector = if (isFavorite) Icons.Filled.Star else Icons.Filled.StarBorder,\n            contentDescription = \"\uc88b\uc544\uc694 \ubc84\ud2bc\",\n            tint = if (isFavorite) Color.Yellow else Color.White,\n            modifier = Modifier\n                .align(Alignment.BottomEnd) \/\/ \uc6b0\uce21 \ud558\ub2e8\uc5d0 \ubc30\uce58 \/ Placed in the bottom right\n                .padding(8.dp)\n                .size(30.dp)\n                .clickable {\n                    \/\/ \ud074\ub9ad \uc2dc \uc0c1\ud0dc\ub97c \ubc18\uc804 (\uc544\uc774\ucf58 \ubcc0\uacbd)\n                    \/\/ Invert the state when clicked (change icon)\n                    isFavorite = !isFavorite\n                }\n        )\n    }\n}\n\n\/\/ == \ud14d\uc2a4\ud2b8 \ubc30\uce58 ,\uc88c\uce21\uc6b0\uce21 \uc774\ubbf8\uc9c0 \ubc0f \uc544\uc774\ucf58 \ubc30\uce58 ==\n\/\/ == Text placement, left and right image and icon placement ==\n@Composable\nfun ImageLoadingExample() {\n    Column(modifier = Modifier.padding(16.dp)) {\n\n        Text(\n            text = \"\uc774\ubbf8\uc9c0 \ub85c\ub4dc \ubc0f \uc0c1\ud0dc \ubcc0\uacbd \uc544\uc774\ucf58 \uc608\uc81c\",\n            modifier = Modifier.fillMaxWidth(),\n            textAlign = TextAlign.Center\n        )\n        Text(\n            text = \"Image loading and state change icon example\",\n            modifier = Modifier.fillMaxWidth(),\n            textAlign = TextAlign.Center\n        )\n\n        Row(\n            modifier = Modifier\n                        .fillMaxWidth()\n                        .align(Alignment.CenterHorizontally),\n            horizontalArrangement = Arrangement.SpaceAround ,\/\/ \uc774\ubbf8\uc9c0 \uc0ac\uc774 \uacf5\uac04 \ud655\ubcf4 \/ Leave space between images\n\n        ) {\n\n            \/\/ ===  \uc88c\uce21 \uc774\ubbf8\uc9c0 \/ left image: AsyncImage (\ub124\ud2b8\uc6cc\ud06c\/Network)  ===\n\n            Card(\n                modifier = Modifier\n                    \/\/.weight(1f)\n                    .padding(end = 0.dp)\n                    .size(150.dp)\n\n\n            ) {\n                Box(\n                    modifier = Modifier,\n                    contentAlignment = Alignment.Center\n                ) {\n                    \/\/ \uc774\ubbf8\uc9c0\uc640 \ud1a0\uae00 \uc544\uc774\ucf58 \ube14\ub7ec\uc624\uae30\n                    \/\/ Blur the image and toggle icon\n                    ImageWithToggleIcon(\n                        imageContent = {\n\n                            AsyncImage(\n                                model = DummyImageUrl,\n                                contentDescription = \"\ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \ubd88\ub7ec\uc628 \uc774\ubbf8\uc9c0\",\n                                contentScale = ContentScale.Crop,\n                                modifier = Modifier.fillMaxSize()\n                            )\n                        }\n                    )\n                }\n            }\n\n\n            \/\/ ===  \uc6b0\uce21 \uc774\ubbf8\uc9c0 \/ right image: Image (\ub85c\uceec \ub9ac\uc18c\uc2a4 \/ local resource)  ===\n\n            Card(\n                modifier = Modifier\n                   \/\/ .weight(1f)\n                    .padding(start = 0.dp)\n                    .size(150.dp)\n\n            ) {\n                Box(\n                    modifier = Modifier,\n                    contentAlignment = Alignment.Center\n                ) {\n                    ImageWithToggleIcon(\n                        imageContent = {\n                            Image(\n                                painter = painterResource(id = R.drawable.cat),\n                                contentDescription = \"\ub85c\uceec\uc774\ubbf8\uc9c0\/Local Image\",\n                                contentScale = ContentScale.Crop,\n                                modifier = Modifier.fillMaxSize()\n                            )\n                        }\n                    )\n                }\n            }\n        }\n    }\n}\n\n\n\/\/ == \uae30\uc874 \ucf54\ub4dc \/ existing code ==\n@Composable\nfun Greeting(name: String, modifier: Modifier = Modifier) {\n    Text(\n        text = \"Hello $name!\",\n        modifier = modifier\n    )\n}\n\n@Preview(showBackground = true)\n@Composable\nfun GreetingPreview() {\n    ImageStateTheme {\n        \/\/Greeting(\"Android\")\n        ImageLoadingExample()\n    }\n}\n\n<\/code><\/pre>\n\n\n\n<p><strong>5.\uc2a4\ud06c\ub9b0\uc0f7 \/ ScreenShot<\/strong><\/p>\n\n\n\n<p>\u2714\ufe0f \uc88c\uce21\uc740 \uc2a4\ud06c\ub9b0\uc0f7\uc774\uace0 \uc6b0\uce21\uc740 \uc548\ub4dc\ub85c\uc774\ub4dc \uc2a4\ud29c\ub514\uc624\uc758 \ud504\ub85c\uc81d\ud2b8\ucc3d \uc785\ub2c8\ub2e4.<br>On the left is a screenshot and on the right is the project window in Android Studio.<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"394\" height=\"880\" data-id=\"2675\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2025\/11\/screenshot.png\" alt=\"\" class=\"wp-image-2675\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2025\/11\/screenshot.png 394w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2025\/11\/screenshot-134x300.png 134w\" sizes=\"auto, (max-width: 394px) 100vw, 394px\" \/><figcaption class=\"wp-element-caption\">screen shot<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"518\" height=\"1024\" data-id=\"2674\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2025\/11\/projectList-518x1024.png\" alt=\"\" class=\"wp-image-2674\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2025\/11\/projectList-518x1024.png 518w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2025\/11\/projectList-152x300.png 152w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2025\/11\/projectList.png 732w\" sizes=\"auto, (max-width: 518px) 100vw, 518px\" \/><figcaption class=\"wp-element-caption\">project window<\/figcaption><\/figure>\n<\/figure>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb \uc0c1\ud0dc\uad00\ub9ac\ub97c \ud1b5\ud574\uc11c \ubcc4 \ubaa8\uc591\uc744 \ub204\ub974\uba74 \uc544\uc774\ucf58 \ubaa8\uc591\uc774 \ubc14\ub01d\ub2c8\ub2e4.When you click on the star shape through status management, the icon shape changes. \ud83d\udc49\ud83c\udffb \ub85c\uceec \uc774\ubbf8\uc9c0\uc640 \ub124\ud2b8\uc6cc\ud06c \uc774\ubbf8\uc9c0\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4.Use local and network images. 1.\uc778\ud130\ub137 \uc0ac\uc6a9\uad8c\ud55c \ucd94\uac00 \/ Add Internet access permission \u2714\ufe0fAndroidManifest.xml 2.\ub77c\uc774\ube0c\ub7ec\ub9ac \ucd94\uac00 \/ Add library \u2714\ufe0fbuild.gradle.kts 3.\ub85c\uceec \uc774\ubbf8\uc9c0 \ub123\uae30 \/ Insert local image \u2714\ufe0f [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,1],"tags":[],"class_list":["post-2666","post","type-post","status-publish","format-standard","hentry","category-kotlin","category-uncategorized","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/2666","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=2666"}],"version-history":[{"count":9,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/2666\/revisions"}],"predecessor-version":[{"id":2678,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/2666\/revisions\/2678"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=2666"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=2666"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=2666"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}