Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android 6.0 Marshmallow stops showing Vertical SeekBar thumb

I've been using this basic wrapper around a SeekBar but find it hides the thumb, or does something funky like make it white on a white background, under Marshmallow.

I used the AS "BlankActivity" wizard to create a project to illustrate this, changing nothing except what is described here, from the defaults. On the left is Lollipop, and the same code is running on the right under Marshmallow:

enter image description here

There is a custom horizontal SeekBar to test if there was a general problem customizing them, which there isn't. The first vertical one on the left has no style, which is fine pre-Marshmallow but not otherwise, the central one explicity uses the Widget.Material.Light.SeekBar style to test if the default somehow wasn't being picked up, and the last one gives a big clue because it uses the old Widget.Holo.SeekBar style where it then appears, albeit looking like it came out a few years ago.

Here's the layout for this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity"
    >

    <com.otamate.seekbarmarshbug.CustomSeekBar
        android:id="@+id/seekBarCustom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

    <com.otamate.seekbarmarshbug.VerticalSeekBar
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_below="@+id/seekBarCustom"
        />

    <com.otamate.seekbarmarshbug.VerticalSeekBar
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:layout_below="@+id/seekBarCustom"
        android:layout_centerHorizontal="true"
        style="@android:style/Widget.Material.Light.SeekBar"
        />

    <com.otamate.seekbarmarshbug.VerticalSeekBar
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/seekBarCustom"
        style="@android:style/Widget.Holo.SeekBar"
        />

</RelativeLayout>

The CustomSeekBar:

package com.otamate.seekbarmarshbug;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.SeekBar;

public class CustomSeekBar extends SeekBar {

    public CustomSeekBar(Context context) {
        super(context);
    }

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

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

and the VerticalSeekBar:

package com.otamate.seekbarmarshbug;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.SeekBar;

public class VerticalSeekBar extends SeekBar {

    public VerticalSeekBar(Context context) {
        super(context);
    }

    public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public VerticalSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(h, w, oldh, oldw);
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }

    protected void onDraw(Canvas c) {
        c.rotate(-90);
        c.translate(-getHeight(), 0);

        super.onDraw(c);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
                setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
                onSizeChanged(getWidth(), getHeight(), 0, 0);
                break;

            case MotionEvent.ACTION_CANCEL:
                break;
        }
        return true;
    }

}
like image 790
Carl Whalley Avatar asked Oct 13 '15 20:10

Carl Whalley


2 Answers

Try this code. It works fine!

<seekBar>
   .....
   android:splitTrack="false"
</seekBar>
like image 72
Palani kumar Avatar answered Oct 18 '22 20:10

Palani kumar


It seems like the marshmallow OS somehow broke the draw on the canvas. I implemented a simple fix.

I made a modification in two methods of my custom VerticalSeekBar

protected void onDraw(Canvas c) {
    c.rotate(-90);
    c.translate(-getHeight(), 0);
    drawThumb(c); //redrawing thumb

    super.onDraw(c);
}

void drawThumb(Canvas canvas) {
    Drawable thumb = getThumb();
    if (thumb != null) {
        Rect thumbBounds = thumb.getBounds();
        canvas.save();
        canvas.rotate(90, thumbBounds.exactCenterX(), thumbBounds.exactCenterY());
        thumb.draw(canvas);
        canvas.restore();
    }
}

Edit: This will only work on Marshmallow devices. If you try to use this on devices that are pre M, they will show two thumbs. If you want this to work on all devices, you will need to completely redraw the thumb by using a custom attribute for the thumb.

Check this github repo for a VerticalSeekBar that works with M https://github.com/3drobotics/AndroidWidgets

like image 25
cbw Avatar answered Oct 18 '22 22:10

cbw