Share
Embed
Jetpack Composeで感じたしあわせ〜♡なところ
subroh_0508
November 27, 2020
Transcript
40 slides
-
গ͚ͩ͠ ࡞ͬͨϞϊએ ˑ$0-03.!45&3 ΞΠυϧϚελʔγϦʔζʹొ͢ΔΞΠυϧͷʜ w ΠϝʔδΧϥʔݕࡧ ϓϨϏϡʔ w ϞόΠϧΛϖϯϥΠτԽɹͰ͖ΔΞϓϦ 8FC൛63-IUUQTJNBTDPMPSNBTUFSXFCBQQ
(JU)VCTVCSPIDPMPSNBTUFS 8FCΞϓϦ൛ϦϦʔεࡁʂ 㾎,PUMJO+4Ͱ࣮ ,PUMJO 㾎μʔΫςʔϚରԠ 㾎ଟݴޠରԠ "OESPJE൛Λ+FUQBDL$PNQPTFͰ࣮தʂ -
͋͠Θͤʹͳͬͨͱ͜Ζ 㾎6*ίϯϙʔωϯτΛখཻ͍͞Ͱѻ͑Δʂ ཻ͕େ͖͍ ը໘୯Ґ ɺখ͞ͳมߋ͕શମʹӨڹΛ༩͕͑ͪ ཻ͕খ͍͞ ෦୯Ґ
ɺมߋ͕ίϯϙʔωϯτʹऩ·Δ $IJQTͱ$IFDLCPYೖΕସ͍͑ͨ ˣ &EJU5FYU$IJQT$IFDLCPYͷ BQQMBZPVU@DPOTUSBJOU˓˓Λશͯमਖ਼ &EJU5FYUमਖ਼ͱؔͳ͍ͷʹʜɹɹ -
͋͠Θͤʹͳͬͨͱ͜Ζ 㾎6*ίϯϙʔωϯτΛখཻ͍͞Ͱѻ͑Δʂ ཻ͕େ͖͍ ը໘୯Ґ ɺখ͞ͳมߋ͕શମʹӨڹΛ༩͕͑ͪ ཻ͕খ͍͞ ෦୯Ґ
ɺมߋ͕ίϯϙʔωϯτʹऩ·Δ @Composable fun SearchBox( params: SearchParams, onParamsChange: (SearchParams) -> Unit = {}, modifier: Modifier = Modifier, ) { Column(Modifier.fillMaxWidth() + modifier) { Spacer(Modifier.preferredHeight(16.dp)) BrandChips(params.brands, ...) Spacer(Modifier.preferredHeight(16.dp)) TypeChips(params.brands, params.types, ... ) } } -
͋͠Θͤʹͳͬͨͱ͜Ζ 㾎6*ίϯϙʔωϯτΛখཻ͍͞Ͱѻ͑Δʂ ཻ͕େ͖͍ ը໘୯Ґ ɺখ͞ͳมߋ͕શମʹӨڹΛ༩͕͑ͪ ཻ͕খ͍͞ ෦୯Ґ
ɺมߋ͕ίϯϙʔωϯτʹऩ·Δ @Composable fun SearchBox( params: SearchParams, onParamsChange: (SearchParams) -> Unit = {}, modifier: Modifier = Modifier, ) { Column(Modifier.fillMaxWidth() + modifier) { Spacer(Modifier.preferredHeight(16.dp)) BrandChips(params.brands, ...) Spacer(Modifier.preferredHeight(16.dp)) TypeChips(params.brands, params.types, ... ) } } $IJQTͱ$IFDLCPYΛίϐϖͰೖΕସ͑ &EJU5FYUʹҰ৮ΕͣมߋͰ͖Δʂɹɹ -
͋͠Θͤʹͳͬͨͱ͜Ζ 㾎7JFX.PEFMɾ$PSPVUJOFTͷαϙʔτ͕ॆ࣮ʂ $PSPVUJOFT val uiModel by viewModel.uiModel.collectAsState(initial =
...) ɹ ColorLists( uiModel.items, onSelect = viewModel::select, onClick = { ... }, onPreviewClick = { ... }, onPenlightClick = { ... }, onAllClick = viewModel::selectAll, modifier = Modifier.fillMaxSize(), ) ྫΠϝʔδΧϥʔͷϦετදࣔ -
͋͠Θͤʹͳͬͨͱ͜Ζ 㾎7JFX.PEFMɾ$PSPVUJOFTͷαϙʔτ͕ॆ࣮ʂ $PSPVUJOFT val uiModel by viewModel.uiModel.collectAsState(initial =
...) ɹ ColorLists( uiModel.items, onSelect = viewModel::select, onClick = { ... }, onPreviewClick = { ... }, onPenlightClick = { ... }, onAllClick = viewModel::selectAll, modifier = Modifier.fillMaxSize(), ) ྫΠϝʔδΧϥʔͷϦετදࣔ 'MPXˠ4UBUFม -
͋͠Θͤʹͳͬͨͱ͜Ζ 㾎7JFX.PEFMɾ$PSPVUJOFTͷαϙʔτ͕ॆ࣮ʂ $PSPVUJOFT val uiModel by viewModel.uiModel.collectAsState(initial =
...) ɹ ColorLists( uiModel.items, onSelect = viewModel::select, onClick = { ... }, onPreviewClick = { ... }, onPenlightClick = { ... }, onAllClick = viewModel::selectAll, modifier = Modifier.fillMaxSize(), ) ྫΠϝʔδΧϥʔͷϦετදࣔ ϦετʹมԽ͕͋ͬͨΒ ࣗಈߋ৽ʂ -
͋͠Θͤʹͳͬͨͱ͜Ζ 㾎4UBUFཧͷ"1*͕͍͍͢ʂ ྫ%SBXFS-BZPVUPO val drawer = findViewById<DrawerLayout>(R.id.drawerLayout) //
։ดॲཧ drawer.closeDrawer(Gravity.LEFT) / drawer.openDrawer(Gravity.RIGHT) // ։ดঢ়ଶͷऔಘ drawer.isDrawerOpen(Gravity.LEFT) ։ดϝιου ঢ়ଶΛ%SBXFS-BZPVUͷΠϯελϯε͕࣋ͭ ˠ7JFXͱ4UBUF͕ີ݁߹ͷঢ়ଶ -
͋͠Θͤʹͳͬͨͱ͜Ζ 㾎4UBUFཧͷ"1*͕͍͍͢ʂ ྫ%SBXFS-BZPVUPO val modalDrawerState = rememberDrawerState(DrawerValue.Closed) ModalDrawerLayout(
drawerState = modalDrawerState, drawerContent = ..., bodyContent = { ... }, ) // ։ดॲཧ modalDrawerState.open() / modalDrawerState.close() // ։ดঢ়ଶͷऔಘ modalDrawerState.isOpen / modalDrawerState.isClosed -
͋͠Θͤʹͳͬͨͱ͜Ζ 㾎4UBUFཧͷ"1*͕͍͍͢ʂ ྫ%SBXFS-BZPVUPO val modalDrawerState = rememberDrawerState(DrawerValue.Closed) ModalDrawerLayout(
drawerState = modalDrawerState, drawerContent = ..., bodyContent = { ... }, ) // ։ดॲཧ modalDrawerState.open() / modalDrawerState.close() // ։ดঢ়ଶͷऔಘ modalDrawerState.isOpen / modalDrawerState.isClosed ։ดϝιου ঢ়ଶΛ%SBXFS4UBUFΫϥε͕࣋ͭ ˠ7JFXͱ4UBUF͕ૄ݁߹ͳঢ়ଶ -
͋͠Θͤʹͳͬͨͱ͜Ζ 㾎3FBDUͱͷੑ͕ߴ͍ʂ +FUQBDL$PNQPTF3FBDUಉ͡એݴత6*ͷࢥ 4UBUFGVMͳ6*ίϯϙʔωϯτͷ࣮ʹ༗༻ͳ"1*͕ଘࡏ 4UBUFΫϥεNVUBCMF4UBUF0Gϝιου
VTF4UBUFϝιου ࣅ௨ͬͨಛΛ࣋ͭͨΊɺ֓೦తͳ෦ͷॻ͖ຯ͕ࣅ͍ͯΔ ˠ8FCΞϓϦઌߦϦϦʔεޙͷ"OESPJE࣮͕ʹݟ͑ͯૣ͔ͬͨʂ ˞ݸਓͷײͰ͢ -
Ծઆ6*ϩδοΫ·Ͱڞ௨ԽͰ͖Δͷ͔ʁ 㾎ݕূ༰ $0-03.!45&3ͷ8FC"OESPJEΞϓϦͷ࣮Λڞ௨Խ 㾎Δ͖͜ͱ .PEFM 3FQPTJUPSZͷ,PUMJO.11ରԠˠྃ 7JFX.PEFMͷ,PUMJO.11ରԠ
8FC൛ͷ࣮Λ7JFX.PEFMʹ߹Θͤͯमਖ਼ CZ,PUMJO.11 -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMΛ,PUMJO.11ʹରԠͨ͠ܗࣜͰ࣮ ڞ௨෦ΛFYQFDUम০ࢠΛ͚࣮ͭͯ expect open class ViewModel constructor(coroutineScope: CoroutineScope?
= null) { protected val viewModelScope: CoroutineScope } DPMPSNBTUFSTIBSFEVUJMJUJFTTSDDPNNPO.BJO -
㾎7JFX.PEFMΛ,PUMJO.11ʹରԠͨ͠ܗࣜͰ࣮ ڞ௨෦ΛFYQFDUम০ࢠΛ͚࣮ͭͯ Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ expect open class ViewModel constructor(coroutineScope: CoroutineScope?
= null) { protected val viewModelScope: CoroutineScope } DPMPSNBTUFSTIBSFEVUJMJUJFTTSDDPNNPO.BJO FYQFDUम০ࢠΛ͚ͭɺ7JFX.PEFMΫϥεͷଘࡏΛఆٛ͢ΔΠϝʔδ "OESPJE+4J04ͦΕͧΕʹ͚࣮ͨࡍͷ࣮ผͰఆٛ͢Δ -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMΛ,PUMJO.11ʹରԠͨ͠ܗࣜͰ࣮ "OESPJE͚ͷ࣮ DPMPSNBTUFSTIBSFEVUJMJUJFTTSDBOESPJE.BJO import androidx.lifecycle.viewModelScope as androidViewModelScope import
androidx.lifecycle.ViewModel as AndroidViewModel actual open class ViewModel actual constructor( coroutineScope: CoroutineScope? ) : AndroidViewModel() { protected actual val viewModelScope = coroutineScope ?: androidViewModelScope } -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMΛ,PUMJO.11ʹରԠͨ͠ܗࣜͰ࣮ "OESPJE͚ͷ࣮ DPMPSNBTUFSTIBSFEVUJMJUJFTTSDBOESPJE.BJO import androidx.lifecycle.viewModelScope as androidViewModelScope import
androidx.lifecycle.ViewModel as AndroidViewModel actual open class ViewModel actual constructor( coroutineScope: CoroutineScope? ) : AndroidViewModel() { protected actual val viewModelScope = coroutineScope ?: androidViewModelScope } "OESPJE͚࣮"OESPJE7JFX.PEFMΛܧঝ -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMΛ,PUMJO.11ʹରԠͨ͠ܗࣜͰ࣮ "OESPJE͚ͷ࣮ DPMPSNBTUFSTIBSFEVUJMJUJFTTSDBOESPJE.BJO import androidx.lifecycle.viewModelScope as androidViewModelScope import
androidx.lifecycle.ViewModel as AndroidViewModel actual open class ViewModel actual constructor( coroutineScope: CoroutineScope? ) : AndroidViewModel() { protected actual val viewModelScope = coroutineScope ?: androidViewModelScope } "OESPJE͚࣮BOESPJE7JFX.PEFM4DPQFΛอ࣋ -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMΛ,PUMJO.11ʹରԠͨ͠ܗࣜͰ࣮ +4͚ͷ࣮ DPMPSNBTUFSTIBSFEVUJMJUJFTTSDKT.BJO actual open class ViewModel actual
constructor(coroutineScope: CoroutineScope?) { protected actual val viewModelScope = coroutineScope ?: MainScope() } -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMΛ,PUMJO.11ʹରԠͨ͠ܗࣜͰ࣮ +4͚ͷ࣮ DPMPSNBTUFSTIBSFEVUJMJUJFTTSDKT.BJO actual open class ViewModel actual
constructor(coroutineScope: CoroutineScope?) { protected actual val viewModelScope = coroutineScope ?: MainScope() } +4͚࣮Կܧঝ͠ͳ͍ɺ.BJO4DPQF Λอ࣋͢Δ ˠ6*ϩδοΫΛهड़͢ΔΫϥεͰϓϥοτϑΥʔϜຖͷ࣮ࠩΛٵऩͰ͖ͨʂ -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎6*ϩδοΫΛ࣮ ύʔιφϧΧϥʔΛ"1*͔Βऔಘ͢Δ1SFWJFX7JFX.PEFMΫϥε class PreviewViewModel( private val repository: IdolColorsRepository,
coroutineScope: CoroutineScope? = null, ) : ViewModel(coroutineScope) { @ExperimentalCoroutinesApi private val _idolsLoadState: MutableStateFlow<LoadState> by lazy { MutableStateFlow(LoadState.Loaded<List<IdolColor>>(listOf())) } @ExperimentalCoroutinesApi val uiModel: Flow<FullscreenPreviewUiModel> get() = _idolsLoadState.map { FullscreenPreviewUiModel(it) } .apply { launchIn(viewModelScope) } fun fetch(ids: List<String>) { val job = viewModelScope.launch(start = CoroutineStart.LAZY) { runCatching { repository.search(ids) } .onSuccess { _idolsLoadState.value = LoadState.Loaded(it) } .onFailure { _idolsLoadState.value = LoadState.Error(it) } } _idolsLoadState.value = LoadState.Loading job.start() } } ࣗલ࣮ͨ͠7JFX.PEFMΛܧঝˠ"OESPJEͱ+4Ͱڞ௨ར༻͕Մೳʂ -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMͷJOKFDU ,PJOΛͬͯ1SFWJFX7JFX.PEFMͷΠϯελϯεΛೖPO class PreviewActivity : AppCompatActivity() { private
val viewModel: PreviewViewModel by viewModel() @ExperimentalMaterialApi @ExperimentalLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Preview(intent.screenType, viewModel, ::finish) } } } -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMͷJOKFDU ,PJOΛͬͯ1SFWJFX7JFX.PEFMͷΠϯελϯεΛೖPO class PreviewActivity : AppCompatActivity() { private
val viewModel: PreviewViewModel by viewModel() @ExperimentalMaterialApi @ExperimentalLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Preview(intent.screenType, viewModel, ::finish) } } } 1SFWJFX7JFX.PEFMͷΠϯελϯεΛ"DUJWJUZʹೖ -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMͷJOKFDU ,PJOΛͬͯ1SFWJFX7JFX.PEFMͷΠϯελϯεΛೖPO class PreviewActivity : AppCompatActivity() { private
val viewModel: PreviewViewModel by viewModel() @ExperimentalMaterialApi @ExperimentalLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Preview(intent.screenType, viewModel, ::finish) } } } !$PNQPTBCMFʹ1SFWJFX7JFX.PEFMͷΠϯελϯεΛ͢ -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMͷJOKFDU ,PJOΛͬͯ1SFWJFX7JFX.PEFMͷΠϯελϯεΛೖPO class FullscreenPreviewContainer : RComponent<FullscreenPreviewProps, FullscreenPreviewState>() {
val viewModel: PreviewViewModel by inject() override fun FullscreenPreviewState.init() { uiModel = FullscreenPreviewUiModel.INITIALIZED } override fun componentDidMount() { launch { viewModel.uiModel.collect { setState { uiModel = it } } } } } -
class FullscreenPreviewContainer : RComponent<FullscreenPreviewProps, FullscreenPreviewState>() { val viewModel: PreviewViewModel by
inject() override fun FullscreenPreviewState.init() { uiModel = FullscreenPreviewUiModel.INITIALIZED } override fun componentDidMount() { launch { viewModel.uiModel.collect { setState { uiModel = it } } } } } Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMͷJOKFDU ,PJOΛͬͯ1SFWJFX7JFX.PEFMͷΠϯελϯεΛೖPO 3$PNQPOFOUˠ"OESPJEͰݴ͏"DUJWJUZతͳΫϥε -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMͷJOKFDU ,PJOΛͬͯ1SFWJFX7JFX.PEFMͷΠϯελϯεΛೖPO class FullscreenPreviewContainer : RComponent<FullscreenPreviewProps, FullscreenPreviewState>() {
val viewModel: PreviewViewModel by inject() override fun FullscreenPreviewState.init() { uiModel = FullscreenPreviewUiModel.INITIALIZED } override fun componentDidMount() { launch { viewModel.uiModel.collect { setState { uiModel = it } } } } } 1SFWJFX7JFX.PEFMͷΠϯελϯεΛ3$PNQPOFOUʹೖ -
Ͳ͏ͬͯڞ௨Խͤͨ͞ͷ͔ 㾎7JFX.PEFMͷJOKFDU ,PJOΛͬͯ1SFWJFX7JFX.PEFMͷΠϯελϯεΛೖPO class FullscreenPreviewContainer : RComponent<FullscreenPreviewProps, FullscreenPreviewState>() {
val viewModel: PreviewViewModel by inject() override fun FullscreenPreviewState.init() { uiModel = FullscreenPreviewUiModel.INITIALIZED } override fun componentDidMount() { launch { viewModel.uiModel.collect { setState { uiModel = it } } } } } VJ.PEFM͕ߋ৽͞ΕΔʹ࠶ඳը͕͔͔ΔΑ͏ઃఆ DPNQPOFOU%JE.PVOUˠ"OESPJEͷPO$SFBUFʹ૬ -
ͭΒ͍ؾ࣋ͪʹͳͬͨͱ͜Ζ 㾎"1*͕සൟʹมΘΔ ϝιουҾ͕ফ໓͢Δ͜ͱৗ൧ࣄ ·͊Ћ൛ͳͷͰʜ αϯϓϧίʔυ͖Ͱ୳͢ͱEFW൛ͷใ্͕Ґʹώοτ͕ͪ͠ 㾎جຊతͳίϯϙʔωϯτʹॏେͳόά͕͍ͬͯͨΓ͢Δ
ྫ5FYU'JFME ผίϯϙʔωϯτʹઌʹϑΥʔΧε͕ͨΔͱ*.&͕ग़ͯ͜ͳ͍ ˢϚδͰࠔͬͯΔ -
ͭΒ͍ؾ࣋ͪʹͳͬͨͱ͜Ζ 㾎.PEJpFSʹ׳Ε͕ඞཁ 7JFXͷݟͨΛมߋ͢ΔϏϧμʔΫϥε ϝιουͷ࣮ߦॱʹΑͬͯNBSHJOͷద༻Ґஔ͕มΘͬͨΓ͢Δ Modifier.preferredHeight(32.dp) .background( color
= MaterialTheme.colors.primary, shape = CircleShape, ) .border(BorderStroke(1.dp, MaterialTheme.colors.primary), CircleShape) .wrapContentHeight(Alignment.CenterVertically) .padding(horizontal = 12.dp) όάʁͦΕͱ༷ʁ +FUQBDL$PNQPTFɺָ͍͠ͷ͚ͩͲຊ൪ར༻ͪΐͬͱͭΒ͍ʜ -
㾎+FUQBDL$PNQPTF Ћ൛ ཉ͍͠ػೳ͔ͳΓἧ͖ͬͯͨʂຊ൪Ͱ͑Δ͍ۙʜʁ 7JFXͱ4UBUFͷ͕ߟྀ͞Εͨίϯϙʔωϯτɺ͍͍͢ʂ 㾎+FUQBDL$PNQPTF 3FBDU ,PUMJO.11
એݴత6*Ͱἧ͑ͨը໘࣮ ,PUMJO.11ඇৗʹ૬ੑ͕Αͦ͞͏ 6*Ҏ֎શͯͷϩδοΫΛ,PUMJOͰ࣮Ͱ͖Δੈք͕ͬͯ͘Δʂʜ͔ ·ͱΊ %SBXFS-BZPVU#BDLESPQͷ࣮͕ຊʹ؆୯ʂ +FUQBDL$PNQPTFͰͷ6*࣮ͷָ͠͞ΛΈͳ͞ΜຯΘͬͯΈͯʜʂ 5IBOLZPVGPSMJTUFOJOH