I want to create a seekbar in android(xml and kotlin).How?

208 Views Asked by At

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()
}

}

1

There are 1 best solutions below

0
Tom On BEST ANSWER

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())
                            }
                        }
                    }
                }