Loading res/layout/fragment_clock_settings.xml +9 −20 Original line number Diff line number Diff line Loading @@ -102,33 +102,22 @@ android:orientation="vertical" android:clipChildren="false"> <FrameLayout <HorizontalScrollView android:id="@+id/color_options_scroll_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:clipChildren="false"> <androidx.recyclerview.widget.RecyclerView android:scrollbars="none"> <LinearLayout android:id="@+id/color_options" android:layout_width="match_parent" android:layout_height="wrap_content" android:clipToPadding="false" android:paddingHorizontal="16dp" android:clipChildren="false" /> <!-- This is just an invisible placeholder put in place so that the parent keeps its height stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows the layout logic to keep the size of the preview container stable as well, which bodes well for setting up the SurfaceView for remote rendering without changing its size after the content is loaded into the RecyclerView. --> <include layout="@layout/clock_color_option" android:layout_marginBottom="16dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="invisible" /> </FrameLayout> android:orientation="horizontal" android:divider="@drawable/horizontal_divider_8dp" android:showDividers="middle"/> </HorizontalScrollView> <SeekBar android:id="@+id/slider" Loading src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt +38 −27 Original line number Diff line number Diff line Loading @@ -16,9 +16,11 @@ package com.android.customization.picker.clock.ui.binder import android.content.res.Configuration import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import android.widget.LinearLayout import android.widget.SeekBar import androidx.core.view.isInvisible import androidx.core.view.isVisible Loading @@ -35,10 +37,9 @@ import com.android.customization.picker.clock.ui.view.ClockSizeRadioButtonGroup import com.android.customization.picker.clock.ui.view.ClockViewFactory import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel import com.android.customization.picker.color.ui.binder.ColorOptionIconBinder import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel import com.android.customization.picker.common.ui.view.ItemSpacing import com.android.wallpaper.R import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter import com.android.wallpaper.picker.option.ui.binder.OptionItemBinder import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.launch Loading @@ -46,6 +47,7 @@ import kotlinx.coroutines.launch object ClockSettingsBinder { private const val SLIDER_ENABLED_ALPHA = 1f private const val SLIDER_DISABLED_ALPHA = .3f private const val COLOR_PICKER_ITEM_PREFIX_ID = 1234 fun bind( view: View, Loading @@ -60,25 +62,7 @@ object ClockSettingsBinder { tabView.adapter = tabAdapter tabView.layoutManager = LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false) tabView.addItemDecoration(ItemSpacing(ItemSpacing.TAB_ITEM_SPACING_DP)) val colorOptionContainerView: RecyclerView = view.requireViewById(R.id.color_options) val colorOptionAdapter = OptionItemAdapter( layoutResourceId = R.layout.clock_color_option, lifecycleOwner = lifecycleOwner, bindIcon = { foregroundView: View, colorIcon: ColorOptionIconViewModel -> val viewGroup = foregroundView as? ViewGroup val night = (view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) viewGroup?.let { ColorOptionIconBinder.bind(viewGroup, colorIcon, night) } } ) colorOptionContainerView.adapter = colorOptionAdapter colorOptionContainerView.layoutManager = LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false) colorOptionContainerView.addItemDecoration(ItemSpacing(ItemSpacing.ITEM_SPACING_DP)) val colorOptionContainerListView: LinearLayout = view.requireViewById(R.id.color_options) val slider: SeekBar = view.requireViewById(R.id.slider) slider.setOnSeekBarChangeListener( object : SeekBar.OnSeekBarChangeListener { Loading Loading @@ -145,18 +129,45 @@ object ClockSettingsBinder { launch { viewModel.colorOptions.collect { colorOptions -> colorOptionAdapter.setItems(colorOptions) colorOptions.forEachIndexed { index, colorOption -> colorOption.payload?.let { payload -> val item = LayoutInflater.from(view.context) .inflate( R.layout.color_option_2, colorOptionContainerListView, false, ) as LinearLayout val darkMode = (view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) ColorOptionIconBinder.bind(item, payload, darkMode) OptionItemBinder.bind( view = item, viewModel = colorOptions[index], lifecycleOwner = lifecycleOwner, foregroundTintSpec = null, ) val id = COLOR_PICKER_ITEM_PREFIX_ID + index item.id = id colorOptionContainerListView.addView(item) } } } } launch { viewModel.selectedColorOptionPosition.collect { selectedPosition -> if (selectedPosition != -1) { // We use "post" because we need to give the adapter item a pass to // update the view. colorOptionContainerView.post { colorOptionContainerView.smoothScrollToPosition(selectedPosition) } val colorOptionContainerListView: LinearLayout = view.requireViewById(R.id.color_options) val selectedView = colorOptionContainerListView.requireViewById<View>( COLOR_PICKER_ITEM_PREFIX_ID + selectedPosition ) selectedView.parent.requestChildFocus(selectedView, selectedView) } } } Loading Loading
res/layout/fragment_clock_settings.xml +9 −20 Original line number Diff line number Diff line Loading @@ -102,33 +102,22 @@ android:orientation="vertical" android:clipChildren="false"> <FrameLayout <HorizontalScrollView android:id="@+id/color_options_scroll_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:clipChildren="false"> <androidx.recyclerview.widget.RecyclerView android:scrollbars="none"> <LinearLayout android:id="@+id/color_options" android:layout_width="match_parent" android:layout_height="wrap_content" android:clipToPadding="false" android:paddingHorizontal="16dp" android:clipChildren="false" /> <!-- This is just an invisible placeholder put in place so that the parent keeps its height stable as the RecyclerView updates from 0 items to N items. Keeping it stable allows the layout logic to keep the size of the preview container stable as well, which bodes well for setting up the SurfaceView for remote rendering without changing its size after the content is loaded into the RecyclerView. --> <include layout="@layout/clock_color_option" android:layout_marginBottom="16dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="invisible" /> </FrameLayout> android:orientation="horizontal" android:divider="@drawable/horizontal_divider_8dp" android:showDividers="middle"/> </HorizontalScrollView> <SeekBar android:id="@+id/slider" Loading
src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt +38 −27 Original line number Diff line number Diff line Loading @@ -16,9 +16,11 @@ package com.android.customization.picker.clock.ui.binder import android.content.res.Configuration import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import android.widget.LinearLayout import android.widget.SeekBar import androidx.core.view.isInvisible import androidx.core.view.isVisible Loading @@ -35,10 +37,9 @@ import com.android.customization.picker.clock.ui.view.ClockSizeRadioButtonGroup import com.android.customization.picker.clock.ui.view.ClockViewFactory import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel import com.android.customization.picker.color.ui.binder.ColorOptionIconBinder import com.android.customization.picker.color.ui.viewmodel.ColorOptionIconViewModel import com.android.customization.picker.common.ui.view.ItemSpacing import com.android.wallpaper.R import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter import com.android.wallpaper.picker.option.ui.binder.OptionItemBinder import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.launch Loading @@ -46,6 +47,7 @@ import kotlinx.coroutines.launch object ClockSettingsBinder { private const val SLIDER_ENABLED_ALPHA = 1f private const val SLIDER_DISABLED_ALPHA = .3f private const val COLOR_PICKER_ITEM_PREFIX_ID = 1234 fun bind( view: View, Loading @@ -60,25 +62,7 @@ object ClockSettingsBinder { tabView.adapter = tabAdapter tabView.layoutManager = LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false) tabView.addItemDecoration(ItemSpacing(ItemSpacing.TAB_ITEM_SPACING_DP)) val colorOptionContainerView: RecyclerView = view.requireViewById(R.id.color_options) val colorOptionAdapter = OptionItemAdapter( layoutResourceId = R.layout.clock_color_option, lifecycleOwner = lifecycleOwner, bindIcon = { foregroundView: View, colorIcon: ColorOptionIconViewModel -> val viewGroup = foregroundView as? ViewGroup val night = (view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) viewGroup?.let { ColorOptionIconBinder.bind(viewGroup, colorIcon, night) } } ) colorOptionContainerView.adapter = colorOptionAdapter colorOptionContainerView.layoutManager = LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false) colorOptionContainerView.addItemDecoration(ItemSpacing(ItemSpacing.ITEM_SPACING_DP)) val colorOptionContainerListView: LinearLayout = view.requireViewById(R.id.color_options) val slider: SeekBar = view.requireViewById(R.id.slider) slider.setOnSeekBarChangeListener( object : SeekBar.OnSeekBarChangeListener { Loading Loading @@ -145,18 +129,45 @@ object ClockSettingsBinder { launch { viewModel.colorOptions.collect { colorOptions -> colorOptionAdapter.setItems(colorOptions) colorOptions.forEachIndexed { index, colorOption -> colorOption.payload?.let { payload -> val item = LayoutInflater.from(view.context) .inflate( R.layout.color_option_2, colorOptionContainerListView, false, ) as LinearLayout val darkMode = (view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) ColorOptionIconBinder.bind(item, payload, darkMode) OptionItemBinder.bind( view = item, viewModel = colorOptions[index], lifecycleOwner = lifecycleOwner, foregroundTintSpec = null, ) val id = COLOR_PICKER_ITEM_PREFIX_ID + index item.id = id colorOptionContainerListView.addView(item) } } } } launch { viewModel.selectedColorOptionPosition.collect { selectedPosition -> if (selectedPosition != -1) { // We use "post" because we need to give the adapter item a pass to // update the view. colorOptionContainerView.post { colorOptionContainerView.smoothScrollToPosition(selectedPosition) } val colorOptionContainerListView: LinearLayout = view.requireViewById(R.id.color_options) val selectedView = colorOptionContainerListView.requireViewById<View>( COLOR_PICKER_ITEM_PREFIX_ID + selectedPosition ) selectedView.parent.requestChildFocus(selectedView, selectedView) } } } Loading