Mi estilo seekBar es Android Widget.AppCompat.SeekBar.Discrete. Tengo mi propio tickMarker pero, como pueden ver, se muestra delante del marcador del pulgar, pero no quiero ver las marcas detrás del pulgar.

Lo que quiero: ingrese la descripción de la imagen aquí

Y lo que tengo

enter image description here

Mi XML:

 <android.support.v7.widget.AppCompatSeekBar
    style="@style/seekbarStyle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:max="4"
    android:padding="4dp"
    android:progress="0"/>

Mi estilo:

<style name="seekbarStyle" parent="Widget.AppCompat.SeekBar.Discrete">
    <item name="tickMark">@drawable/seekbar_tickmark</item>
    <item name="android:thumb">@drawable/circle</item>
</style>
11
FarshidABZ 5 ene. 2017 a las 19:45

4 respuestas

La mejor respuesta

Este es un error de AppCompatSeekBar. Resolví este problema con una clase personalizada que extiende AppCompatSeekBar:

public class CustomSeekBar extends AppCompatSeekBar {

    private Drawable mTickMark;

    public CustomSeekBar(Context context) {
        this(context, null);
    }

    public CustomSeekBar(Context context, AttributeSet attrs) {
        this(context, attrs, android.support.v7.appcompat.R.attr.seekBarStyle);
    }

    public CustomSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        applyAttributes(attrs, defStyleAttr);
    }

    private void applyAttributes(AttributeSet rawAttrs, int defStyleAttr)
    {
        TypedArray attrs = getContext().obtainStyledAttributes(rawAttrs, R.styleable.CustomSeekBar, defStyleAttr, 0);
        try {
            mTickMark = attrs.getDrawable(R.styleable.CustomSeekBar_tickMarkFixed);
        } finally {
            attrs.recycle();
        }
    }

    @Override
    protected synchronized void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawTickMarks(canvas);
    }

    @Override
    public int getThumbOffset() {
        return super.getThumbOffset();
    }

    void drawTickMarks(Canvas canvas) {
        if (mTickMark != null) {
            final int count = getMax();
            if (count > 1) {
                final int w = mTickMark.getIntrinsicWidth();
                final int h = mTickMark.getIntrinsicHeight();
                final int halfThumbW = getThumb().getIntrinsicWidth() / 2;
                final int halfW = w >= 0 ? w / 2 : 1;
                final int halfH = h >= 0 ? h / 2 : 1;
                mTickMark.setBounds(-halfW, -halfH, halfW, halfH);
                final float spacing = (getWidth() - getPaddingLeft() - getPaddingRight() + getThumbOffset() * 2 - halfThumbW * 2) / (float) count;
                final int saveCount = canvas.save();
                canvas.translate(getPaddingLeft() - getThumbOffset() + halfThumbW, getHeight() / 2);
                for (int i = 0; i <= count; i++) {
                    if(i!=getProgress())
                        mTickMark.draw(canvas);
                    canvas.translate(spacing, 0);
                }
                canvas.restoreToCount(saveCount);
            }
        }
    }
}

Con las attrs.xml:

<resources>
    <declare-styleable name="CustomSeekBar">
        <attr name="tickMarkFixed" format="reference"/>
    </declare-styleable>
</resources>

Y en el diseño debe usar tickMarkFixed en lugar de tickMark .

12
andrea689 9 dic. 2017 a las 09:23

Parece que el problema es que el widget AppCompatSeekBar llama super, que dibuja el pulgar y luego dibuja los ticks sobre él.

Aquí hay una clase de Kotlin que soluciona el problema al volver a dibujar el pulgar sobre el lienzo (que, en este punto, tiene el pulgar y luego las marcas dibujadas sobre él:

class SeekBar @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = android.R.attr.seekBarStyle
) : AppCompatSeekBar(context, attrs, defStyleAttr) {
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        drawThumb(canvas)
    }

    private fun drawThumb(canvas: Canvas) {
        if (thumb != null) {
            val saveCount = canvas.save()
            canvas.translate((paddingLeft - thumbOffset).toFloat(), paddingTop.toFloat())
            thumb.draw(canvas)
            canvas.restoreToCount(saveCount)
        }
    }
}

Nota: esta solución puede dejar algunos artefactos porque el pulgar se dibuja dos veces. Una solución alternativa podría ser definir un pulgar secundario y usarlo mientras se oculta el pulgar original.

1
Eran Boudjnah 12 abr. 2020 a las 07:50

Encontré una buena biblioteca aquí:

IndicatorSeekBar

0
FarshidABZ 24 dic. 2017 a las 13:44

Compartiré la solución en kotlin , para una mejor solución y para evitar el marcador antes del uso del pulgar:

    if (i > progress)

El código completo:

    class CustomSeekBar @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0) : AppCompatSeekBar(context, attrs, defStyle) {
private var mTickMark: Drawable? = null

init {
    applyAttributes(attrs, defStyle)
}

private fun applyAttributes(rawAttrs: AttributeSet?, defStyleAttr: Int) {
    val attrs = context.obtainStyledAttributes(rawAttrs, R.styleable.CustomSeekBar, defStyleAttr, 0)
    try {
        mTickMark = attrs.getDrawable(R.styleable.CustomSeekBar_customTickMark)
    } finally {
        attrs.recycle()
    }
}


override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    drawTickMarks(canvas)
}


private fun drawTickMarks(canvas: Canvas) {
    if (mTickMark != null) {
        val count = max

        val w = mTickMark!!.intrinsicWidth
        val h = mTickMark!!.intrinsicHeight
        val halfThumbW = thumb.intrinsicWidth / 2
        val halfW = if (w >= 0) w / 2 else 1
        val halfH = if (h >= 0) h / 2 else 1
        mTickMark!!.setBounds(-halfW, -halfH, halfW, halfH)
        val spacing = (width - paddingLeft - paddingRight + thumbOffset * 2 - halfThumbW * 2) / count.toFloat()
        val saveCount = canvas.save()
        canvas.translate((paddingLeft - thumbOffset + halfThumbW).toFloat(), (height / 2).toFloat())
        for (i in 0..count) {
            if (i > progress)
                mTickMark!!.draw(canvas)
            canvas.translate(spacing, 0F)
        }
        canvas.restoreToCount(saveCount)
    }
}
}

Recuerde crear el atributo en el archivo attrs.xml en res / values , así:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomSeekBar">
        <attr name="customTickMark" format="integer" />
    </declare-styleable>
</resources>
0
LinuxFelipe-COL 17 ene. 2019 a las 18:36