Create your own Mini Player
In this tutorial, we will explain how to create your own mini player on your Android project.
Views are going to use many android resources as
drawable
dimens
and colors
from the StayTuned Android SDK. Feel free to change with your own resources to match your application style.The tutorial requires the usage of
LiveData
Our goal is to create the view class and layout to have a MiniPlayer as below :

We can describe the player as follows :
- On the top, a progress bar to display the current
STTrack
progression - On the left, the image of the current
STTrack
- The first line is the title of the current
STTrack
- The second line is the title of the current
STContent
- On the right, the main button to control the
STPlayer
To begin, we need to create the 2 files we are going to use for the MiniPlayer.
Lets create a
mini_player.xml
in your layout
resource folder as follows :<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mini_player_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:clickable="true"
android:focusable="true"
android:orientation="vertical">
</LinearLayout>
And a class
MiniPlayer.kt
as follows : class MiniPlayer(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) {
init {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
inflater.inflate(R.layout.mini_player, this, true)
}
}
For now, we only have an empty view.
We are not going to explain the layout file view by view, instead we are going to see how to change the style of the layout. You can find the full layout file at : Link to Layout File
You can change the background color of the MiniPlayer by updating the background property :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mini_player"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:background="@android:color/white" > <!-- Update with your color here -->
The vizualizer is the view animated on the image of the track. Update the property
app:barColor
<com.staytuned.core.ui.STLineBarVisualizer
android:id="@+id/mini_player_visualizer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_margin="@dimen/st_size_24"
app:barColor="@android:color/white" /> <!-- Update with your color here -->
You can update the color and the font of every
TextView
on the miniplayer, as follows : <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
..
android:fontFamily="?attr/fontFamilySemiBold" <!-- Update with your font here -->
android:textColor="@color/stTextDefault" /> <!-- Update with your color here -->
You can update the progress color as follows :
<ProgressBar
android:id="@+id/mini_player_progress"
style="@android:style/Widget.ProgressBar.Horizontal"
..
android:layout_width="match_parent"
android:progressDrawable="@drawable/st_seek_style_transparent"
android:progressTint="@color/colorPrimary" /> <!-- Update with your progress color here -->
The main button of the MiniPlayer has a background color (the gray circle by default), multiple Icons (Play, Pause) and a ProgressBar loader. You can update their color as follows :
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/mini_player_play_toggle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/st_circle_gray"
app:srcCompat="@drawable/st_ic_play"
..
android:backgroundTint="@color/stGrayLight" <!-- Update this to change background color -->
android:tint="@android:color/black" /> <!-- Update this to change icons color -->
<ProgressBar
android:id="@+id/mini_player_play_loader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:indeterminate="true"
android:visibility="gone"
tools:visibility="visible"
android:indeterminateTint="@android:color/black" /> <!-- Update this to change loader color -->
Now that we have a complete layout view file, we have to connect the views with the SDK values. You can find the full code at : Link to Class File
First of all, we want the MiniPlayer to hide itself when the Player is not playing any track. We need to add an observer to the currentTrack of the Player. If it's
null
, we hide the MiniPlayer, else we show it.override fun onAttachedToWindow() {
super.onAttachedToWindow()
STPlayer.getInstance()?.currentTrack?.observe(context as LifecycleOwner, Observer {
visibility = if (it == null) {
View.GONE
} else {
View.VISIBLE
}
})
}
Now we need to connect the 2
TextView
(mini_player_track_title
and mini_player_content_title
) and the ImageView
(mini_player_image
) with the current track and content. We add code to the currentTrack
observer we've added before and add a new observer to currentContent
override fun onAttachedToWindow() {
super.onAttachedToWindow()
STPlayer.getInstance()?.currentTrack?.observe(context as LifecycleOwner, Observer {
visibility = if (it == null) {
View.GONE
} else {
View.VISIBLE
}
mini_player_track_title.text = it?.title
Glide.with(this).load(it?.imgSrc).centerInside().into(mini_player_image)
})
STPlayer.getInstance()?.currentContent?.observe(context as LifecycleOwner, Observer {
mini_player_content_title.text = it?.title
})
}
We want the progress to be binded with the Player current track progress. For this, we add an observer to the player
currentTime
override fun onAttachedToWindow() {
super.onAttachedToWindow()
..
STPlayer.getInstance()?.currentTime?.observe(context as LifecycleOwner, Observer {
mini_player_progress.progress = STPlayer.getInstance()?.getAudioProgress()?.toInt() ?: 0
})
}
The player has multiple states.
Playing
, Paused
and Loading
. When it's playing, we want the Visualizer to animate and the button to display a pause icon. When it's paused, we want the Visualizer to stop and the button to display a play icon, and when it's loading, we want the button to be replaced by a loader. For this, we add an observer to the Player
currentState
override fun onAttachedToWindow() {
super.onAttachedToWindow()
..
STPlayer.getInstance()?.currentState?.observe(context as LifecycleOwner, Observer {
setVisualizerState()
setButtonState()
})
}
private fun setVisualizerState() {
// pause or play the visualizer animation by the player state
mini_player_visualizer.isPlaying = STPlayer.getInstance()?.isPlaying() == true
}
private fun setButtonState() {
val player = STPlayer.getInstance()
when {
// When it's playing, we show a pause button and hide the loader
player?.isPlaying() == true && !player.isLoading() -> {
mini_player_play_toggle.visibility = View.VISIBLE
mini_player_play_loader.visibility = View.GONE
mini_player_play_toggle.setImageResource(com.staytuned.R.drawable.st_ic_pause)
}
// When it's loading, we hide the button and show the loader
player?.isLoading() == true -> {
mini_player_play_toggle.visibility = View.GONE
mini_player_play_loader.visibility = View.VISIBLE
}
// Else we consider the state as PAUSED, we show a play icon and hide the loader
else -> {
mini_player_play_toggle.visibility = View.VISIBLE
mini_player_play_loader.visibility = View.GONE
mini_player_play_toggle.setImageResource(com.staytuned.R.drawable.st_ic_play)
}
}
}
Now the button displays a nice icon or a loader for each state, we want the button to dispach the right action to the player. For this, we need to add a click listener on the button.
init {
..
mini_player_play_toggle.setOnClickListener {
togglePlayPause()
}
}
..
private fun togglePlayPause() {
if (STPlayer.getInstance()?.isPlaying() == true) {
STPlayer.getInstance()?.stop()
} else {
STPlayer.getInstance()?.resume()
}
}
To finish this tutorial, we want the fully expanded Player to open when the user click anywhere on the MiniPlayer. For this, we need to add a click listener on the root view.
init {
..
mini_player.setOnClickListener {
STPlayer.getInstance()?.launchUI(it.context)
}
}
Now, you have a fully working MiniPlayer with your own theme. The last thing you have to do is to add your custom MiniPlayer to the screen layout you want it to be displayed.
..
<com.staytuned.demo.views.MiniPlayer
android:layout_width="match_parent"
android:layout_height="wrap_content" />
..
Demo Application source code : Link to Github Repository
MiniPlayer xml file : Link to Layout File
MiniPlayer class file : Link to Class File
Last modified 2yr ago