ui: animate selection

Animate the check mark and background change when a item is selected.

This produces a nicer UX overall. If possible, I'm planning to also
port this to the other indicators in ImageGroup, albeit doing that is
signifigantly harder.
This commit is contained in:
Alexander Capehart 2022-12-05 04:24:18 +00:00
parent a02490ae18
commit f5ec295b2c
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
6 changed files with 45 additions and 9 deletions

View file

@ -26,7 +26,9 @@ import android.widget.FrameLayout
import android.widget.ImageView import android.widget.ImageView
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
import androidx.core.view.updateMarginsRelative import androidx.core.view.updateMarginsRelative
import androidx.transition.TransitionManager
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.transition.MaterialFade
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
@ -142,6 +144,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
private fun invalidatePlayingIndicator() { private fun invalidatePlayingIndicator() {
if (isSelected) { if (isSelected) {
// TODO: Animate the other indicators?
customView?.alpha = 0f customView?.alpha = 0f
inner.alpha = 0f inner.alpha = 0f
playingIndicator.alpha = 1f playingIndicator.alpha = 1f
@ -153,7 +156,26 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
} }
private fun invalidateSelectionIndicator() { private fun invalidateSelectionIndicator() {
selectionIndicator.alpha = if (isActivated) 1f else 0f val targetVis: Int
val targetDuration: Long
if (isActivated) {
targetVis = VISIBLE
targetDuration = 150L
} else {
targetVis = INVISIBLE
targetDuration = 84L
}
if (selectionIndicator.visibility == targetVis) {
return
}
TransitionManager.beginDelayedTransition(this, MaterialFade().apply {
duration = targetDuration
})
selectionIndicator.visibility = targetVis
} }
fun bind(song: Song) { fun bind(song: Song) {

View file

@ -43,7 +43,6 @@ class SongViewHolder private constructor(private val binding: ItemSongBinding) :
binding.songName.text = item.resolveName(binding.context) binding.songName.text = item.resolveName(binding.context)
binding.songInfo.text = item.resolveArtistContents(binding.context) binding.songInfo.text = item.resolveArtistContents(binding.context)
binding.songAlbumCover.setOnClickListener { listener.onSelect(item) }
binding.songMenu.setOnClickListener { listener.onOpenMenu(item, it) } binding.songMenu.setOnClickListener { listener.onOpenMenu(item, it) }
binding.root.apply { binding.root.apply {
setOnClickListener { listener.onItemClick(item) } setOnClickListener { listener.onItemClick(item) }
@ -88,7 +87,6 @@ class AlbumViewHolder private constructor(private val binding: ItemParentBinding
binding.parentName.text = item.resolveName(binding.context) binding.parentName.text = item.resolveName(binding.context)
binding.parentInfo.text = item.resolveArtistContents(binding.context) binding.parentInfo.text = item.resolveArtistContents(binding.context)
binding.parentImage.setOnClickListener { listener.onSelect(item) }
binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) } binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) }
binding.root.apply { binding.root.apply {
setOnClickListener { listener.onItemClick(item) } setOnClickListener { listener.onItemClick(item) }
@ -145,7 +143,6 @@ class ArtistViewHolder private constructor(private val binding: ItemParentBindin
binding.context.getPlural(R.plurals.fmt_album_count, item.albums.size) binding.context.getPlural(R.plurals.fmt_album_count, item.albums.size)
} }
binding.parentImage.setOnClickListener { listener.onSelect(item) }
binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) } binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) }
binding.root.apply { binding.root.apply {
setOnClickListener { listener.onItemClick(item) } setOnClickListener { listener.onItemClick(item) }
@ -196,7 +193,6 @@ class GenreViewHolder private constructor(private val binding: ItemParentBinding
binding.context.getPlural(R.plurals.fmt_artist_count, item.artists.size), binding.context.getPlural(R.plurals.fmt_artist_count, item.artists.size),
binding.context.getPlural(R.plurals.fmt_song_count, item.songs.size)) binding.context.getPlural(R.plurals.fmt_song_count, item.songs.size))
binding.parentImage.setOnClickListener { listener.onSelect(item) }
binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) } binding.parentMenu.setOnClickListener { listener.onOpenMenu(item, it) }
binding.root.apply { binding.root.apply {
setOnClickListener { listener.onItemClick(item) } setOnClickListener { listener.onItemClick(item) }

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="0.12" android:color="?attr/colorPrimary" android:state_activated="true"/> <item android:alpha="0.12" android:color="?attr/colorPrimary" android:state_activated="true"/>
<item android:color="?attr/colorSurface" />
</selector> </selector>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
android:enterFadeDuration="150"
android:exitFadeDuration="150">
<item
android:id="@+id/pressed"
android:state_activated="true">
<shape android:shape="rectangle">
<solid android:color="@color/sel_item_activated_bg" />
</shape>
</item>
<item
android:id="@+id/def">
<shape android:shape="rectangle">
<solid android:color="@color/sel_item_activated_bg" />
</shape>
</item>
</animated-selector>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/sel_activatable_background" /> <item android:drawable="@drawable/sel_item_ripple_bg" />
<item android:drawable="?attr/selectableItemBackground" /> <item android:drawable="?attr/selectableItemBackground" />
</layer-list> </layer-list>

View file

@ -5,9 +5,9 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:paddingStart="@dimen/spacing_mid_large" android:paddingStart="@dimen/spacing_large"
android:paddingTop="@dimen/spacing_medium" android:paddingTop="@dimen/spacing_medium"
android:paddingEnd="@dimen/spacing_mid_large" android:paddingEnd="@dimen/spacing_large"
android:paddingBottom="@dimen/spacing_medium"> android:paddingBottom="@dimen/spacing_medium">
<org.oxycblt.auxio.image.ImageGroup <org.oxycblt.auxio.image.ImageGroup