アプリのアイコンが付いていないとコードを書く気が出ない・・・そんなときに、とりあえずそれっぽいアイコンをさくっく作成する方法です。先日、iOSでやったので、今回はAndroidでもやってみました。
↑ やる気がでないやつ
アプリアイコンの作成の流れ
- アイコン画像を表示するViewを作成
- Viewのスナップショットをファイルに保存(PNG)
- Android Studioでアイコン画像を設定
アイコン画像を表示するViewの作成
Jetpack Composeでマテリアルアイコンを使って適当なアイコンをViewに表示して、背景色にグラデーションをかけるだけです。
@Composable
fun AppIconView(iconVector: ImageVector, baseColor: Color, modifier: Modifier = Modifier) {
val endColor = baseColor.copy(alpha = 0.7f)
BoxWithConstraints(
modifier = modifier
) {
val boxWith = constraints.maxWidth.toFloat()
val boxHeight = constraints.maxHeight.toFloat()
val gradientBrush = Brush.linearGradient(
colors = listOf(baseColor, endColor),
start = Offset(boxWith / 2, boxHeight / 2),
end = Offset(boxWith / 2, 0f))
Box(
modifier = Modifier
.fillMaxSize()
.background(brush = gradientBrush),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = iconVector,
contentDescription = null,
tint = Color.White,
modifier = Modifier.fillMaxSize(0.4f)
)
}
}
}
@Preview(showBackground = true)
@Composable
fun IconViewPreview() {
Column {
AppIconView(
iconVector = Icons.Default.Draw,
baseColor = Color(235, 78, 61),
modifier = Modifier.size(200.dp).padding(8.dp)
)
AppIconView(
iconVector = Icons.Default.Train,
baseColor = Color(101, 196, 102),
modifier = Modifier.size(200.dp).padding(8.dp)
)
AppIconView(
iconVector = Icons.Default.Sailing,
baseColor = Color(52, 120, 246),
modifier = Modifier.size(200.dp).padding(8.dp)
)
}
}
すべてのマテリアルアイコンを使用できるようにする
デフォルトではCoreライブラリに入っている基本アイコンのみのため、すべてのマテリアルアイコンを使用するためには追加パッケージが必要です。
implementation("androidx.compose.material:material-icons-extended")
Viewのキャプチャをファイルに保存
ファイル保存用のボタンを設置し、 アイコンのキャプチャをファイルに保存します。キャプチャ対象をAppIconViewだけに絞るために、AndroidViewでラップしViewのインスタンスを取得します。画像ファイルは端末の画像フォルダーに保存されます(エミュレータ時のファイルパスは後述)。
アイコンや色を変えるUIは今回用意していなので、コード上のiconとbaseColorを直接書き換えます。
@Composable
fun MainView() {
val scope = rememberCoroutineScope()
val context = LocalContext.current
val density = LocalDensity.current
var composeViewRef by remember { mutableStateOf<ComposeView?>(null) }
var isGranted by remember { mutableStateOf(true) }
val icon: ImageVector = Icons.Default.Draw
val requestPermissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) {
if (it) {
isGranted = true
} else {
Toast.makeText(context, "Permission denied", Toast.LENGTH_SHORT).show()
}
}
isGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
true
} else {
ContextCompat.checkSelfPermission(
context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
}
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
contentAlignment = Alignment.Center
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
// キャプチャ時にインスタンスを取得するために、AndroidViewでアイコンを描画
AndroidView(
factory = { ctx ->
ComposeView(ctx).apply {
layoutParams = ViewGroup.LayoutParams(
(300 * density.density).toInt(),
(300 * density.density).toInt()
)
setContent {
AppIconView(
iconVector = icon,
baseColor = Color(235, 149, 0),
modifier = Modifier
.size(300.dp)
.background(Color.White)
)
}
composeViewRef = this
}
}
)
Text(icon.name)
}
Button(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(top = 16.dp),
onClick = {
if (isGranted) {
val view = composeViewRef
view?.let {
val bitmap = it.drawToBitmap()
scope.launch {
saveImageToGallery(context, bitmap)
}
}
} else {
requestPermissionLauncher.launch(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}
) {
Text("Save Image")
}
}
}
fun saveImageToGallery(context: Context, bitmap: Bitmap) {
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "Icon_${System.currentTimeMillis()}.png")
put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
}
val uri = context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
uri?.let {
val outputStream: OutputStream? = context.contentResolver.openOutputStream(it)
outputStream.use { stream ->
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
Toast.makeText(context, "Image file saved to: " + it.path, Toast.LENGTH_LONG).show()
}
}
}
エミュレータで実行している場合の保存場所
Androidエミュレータでアプリを実行すると、アプリの画像ファイルはAndroid StudioのDevice Explorerで参照できます。
storage > emulated > 0 > Picturesに保存されているので、pngファイルを右クリックしてダウンロードフォルダーなどに保存します。
画像ファイルをAndroid StudioのImage Assetに設定
- Android StudioのFileメニューから、New > Image Asset を選択して Asset Studio を起動します。
- 画像ファイルをPathに設定します。上書きするかの警告は無視して問題ありません。
- あとはデフォルトのまま Next > Finish と進めると完了です。
完成サンプル
おしまい〜!
サンプルコード一式
iOS版はこちら