I want to create a seekbar like the picture below in android(xml and kotlin).How? Also I need to do the kotlin portions in a custom adapter.
I tried using github libraries,but it seemed to be not working at all,or I am confused as to how to implement it in my project.
Please help or guide me to create a seekbar like in the picture.enter image description here
I have somthing like this from chatGPT,but I need to make it look like the picture above.HOw??
class SeekbarView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) {
private val waveColor = Color.BLUE
private val thumbColor = Color.RED
private val progressPath = Path()
private val thumbPath = Path()
private val progressPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.FILL
color = waveColor
}
private val thumbPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.FILL
color = thumbColor
}
private val thumbRect = RectF()
private var progress = 0f
private var maxProgress = 100f
init {
// Set up any additional initialization here
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val desiredWidth = suggestedMinimumWidth + paddingLeft + paddingRight
val desiredHeight = suggestedMinimumHeight + paddingTop + paddingBottom
val measuredWidth = measureDimension(desiredWidth, widthMeasureSpec)
val measuredHeight = measureDimension(desiredHeight, heightMeasureSpec)
setMeasuredDimension(measuredWidth, measuredHeight)
}
private fun measureDimension(desiredSize: Int, measureSpec: Int): Int {
val mode = MeasureSpec.getMode(measureSpec)
val size = MeasureSpec.getSize(measureSpec)
return when (mode) {
MeasureSpec.EXACTLY -> size
MeasureSpec.AT_MOST -> desiredSize.coerceAtMost(size)
MeasureSpec.UNSPECIFIED -> desiredSize
else -> desiredSize
}
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val width = width.toFloat()
val height = height.toFloat()
// Draw waveform
progressPath.reset()
val waveHeight = height / 2 // Height of the waveform
val waveStep = width / 100 // Width of each waveform segment
val centerY = height / 2 // Vertical center position
progressPath.moveTo(0f, centerY)
for (i in 0..50) {
val x = i * waveStep
val y = centerY + Math.sin(x / width * 2 * Math.PI + progress / maxProgress * 2 * Math.PI) * waveHeight
progressPath.lineTo(x, y.toFloat())
}
progressPath.lineTo(width, centerY)
progressPath.close()
canvas.drawPath(progressPath, progressPaint)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
val x = event.x
when (event.action) {
MotionEvent.ACTION_DOWN -> {
return true
}
MotionEvent.ACTION_MOVE -> {
val progress = x / width * maxProgress
setProgress(progress.coerceIn(0f, maxProgress))
invalidate()
return true
}
MotionEvent.ACTION_UP -> {
// Handle thumb release event here
return true
}
}
return super.onTouchEvent(event)
}
fun setProgress(progress: Float) {
this.progress = progress
invalidate()
}
fun setMaxProgress(maxProgress: Float) {
this.maxProgress = maxProgress
invalidate()
}
}
I used a github library https://github.com/massoudss/waveformSeekBar
And in gradle(app)- Paste this
implementation 'com.github.massoudss:waveformSeekBar:5.0.2'
implementation 'com.github.lincollincol:amplituda:2.2.2'
In gradle(project) - Paste this
buildscript
{
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
classpath 'com.google.gms:google-services:4.3.14'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0"
}
}
In xml file,use
<ImageView
android:id="@+id/ivPause"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginStart="8dp"
android:layout_marginTop="35dp"
android:src="@drawable/ic_pause"
android:visibility="gone"
/>
<ImageView
android:id="@+id/ivPlay"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginStart="8dp"
android:layout_marginTop="35dp"
android:src="@drawable/ic_play"
android:visibility="visible"
/>
<com.masoudss.lib.WaveformSeekBar
android:id="@+id/seekBar"
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_marginStart="20dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="10dp"
android:visibility="visible"
app:wave_background_color="@color/light_green"
app:wave_corner_radius="5dp"
app:wave_gap="2dp"
app:wave_gravity="center"
app:wave_max_progress="100"
app:wave_min_height="5dp"
app:wave_padding_Bottom="2dp"
app:wave_padding_left="2dp"
app:wave_padding_right="2dp"
app:wave_padding_top="2dp"
app:wave_progress="50"
app:wave_progress_color="@color/lead_list_followup"
app:wave_visible_progress="50"
app:wave_width="3dp" />
Now if you want to use this seekbar to play audio file,Use the code below:
binding.seekBar.setSampleFrom(File("/storage/self/primary/Music/Voice Recorder/darari ringtone.mp3"))
var mp: MediaPlayer? = null
val handler = Handler()
binding.ivPlay.setOnClickListener {
if (mp == null) {
mp = MediaPlayer.create(
context,
Uri.parse("/storage/self/primary/Music/Voice Recorder/darari ringtone.mp3")
)
}
mp?.start()
binding.seekBar.maxProgress = mp!!.duration.toFloat()
handler.postDelayed(object : Runnable {
override fun run() {
try {
binding.seekBar.progress = mp!!.currentPosition.toFloat()
handler.postDelayed(this, 600)
if (!mp!!.isPlaying) {
handler.removeCallbacksAndMessages(null)
binding.ivPause.hide()
binding.ivPlay.show()
}
} catch (e: Exception) {
binding.seekBar.progress = 0F
}
}
}, 0)
binding.ivPause.show()
binding.ivPlay.hide()
}
binding.ivPause.setOnClickListener {
if (mp?.isPlaying == true) {
mp?.pause()
}
binding.ivPlay.visibility = View.VISIBLE
binding.ivPause.visibility = View.GONE
}
binding.seekBar.apply {
onProgressChanged = object : SeekBarOnProgressChanged {
override fun onProgressChanged(
waveformSeekBar: WaveformSeekBar,
progress: Float,
fromUser: Boolean
) {
if (fromUser) {
mp?.seekTo(progress.toInt())
}
}
}
}