seeking时如何隐藏SeekBar的tickmark?

How to hide tickmark of SeekBar when seeking?

我想设计一个自定义的Seekbar,如下图所示:

但是,这是我的输出:

我有一些问题。当我使用 SeekBar 向前查找时,刻度线仍然存在,我想隐藏它。我的另一个问题是两个刻度线被放置在 SeekBar 之外。另外,我想把每个步骤的编号放在SeekBar上面,在SeekBar上面。我尝试了下面的代码,但只有在 onProgressChanged 方法中才能获得 SeekBar 的正确位置。

 private fun setNumber(){
    for(i in 0..10 step 2){
        var pos=i*(seekbar.width - 2 * seekbar.thumbOffset)/seekbar.max
        Log.e(TAG,"pos $i= $pos")
        when(i){
            0 -> {
                txt_label_zero.setX(seekbar.x + pos + seekbar.thumbOffset / 2)
            }
            2 -> {
                txt_label_two.setX(seekbar.x + pos + seekbar.thumbOffset / 2)
            }
            4 ->{
                txt_label_four.setX(seekbar.x + pos + seekbar.thumbOffset / 2)
            }
            6 ->{
                txt_label_six.setX(seekbar.x + pos + seekbar.thumbOffset / 2)
            }
            8 ->{
                txt_label_eight.setX(seekbar.x + pos + seekbar.thumbOffset / 2)
            }
            10 ->{
                txt_label_ten.setX(seekbar.x + pos + seekbar.thumbOffset / 2)
            }
        }

    }
}

private fun setSeekbar() {

    seekbar?.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
        override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {

        }

        override fun onStartTrackingTouch(seekBar: SeekBar) {

        }

        override fun onStopTrackingTouch(seekBar: SeekBar) {


        }
    })
}

此处可绘制和 xml 布局: drw_bg_seekbar:

 <?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background"
          android:gravity="center_vertical">
        <shape android:shape="rectangle"
              >
            <corners android:radius="15dp"/>
            <size android:height="30dp" />
            <solid android:color="@color/mainGrey" />
        </shape>
    </item>
    <item android:id="@android:id/progress"
          android:gravity="center_vertical">
        <scale android:scaleWidth="100%">
            <selector>
                <item>
                    <shape android:shape="rectangle"
                         >
                        <corners android:radius="15dp"/>
                        <size android:height="30dp" />
                        <solid android:color="@color/lightGreen" />
                    </shape>
                </item>
            </selector>
        </scale>
    </item>
</layer-list>

drw_thumb_seekbar:

    <shape
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval"
        >
    <solid
            android:color="@color/darkGrey" />
    <size
            android:width="24dp"
            android:height="24dp" />
</shape>

drw_bg_tickmark:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
   android:shape="oval"
   android:tint="@color/darkGrey">
<corners android:radius="4dp"/>
<size android:width="16dp"
      android:height="16dp" />
<solid android:color="@color/darkGrey" />

我的布局:

    <RelativeLayout 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:layout_width="match_parent"
             android:layout_height="match_parent"
             tools:context=".OneFragment"
>


    <LinearLayout
            android:id="@+id/lay_number"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_marginTop="40dp"
            android:visibility="visible"
    >
        <TextView
                android:id="@+id/txt_label_zero"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="0"
        />
        <TextView
                android:id="@+id/txt_label_two"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="2"
        />
        <TextView
                android:id="@+id/txt_label_four"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="4"
        />
        <TextView
                android:id="@+id/txt_label_six"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="6"
        />
        <TextView
                android:id="@+id/txt_label_eight"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="8"
        />
        <TextView
                android:id="@+id/txt_label_ten"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="10"
        />
    </LinearLayout>
    <androidx.appcompat.widget.AppCompatSeekBar
            android:id="@+id/seekbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:layout_marginTop="10dp"
            android:layout_below="@+id/lay_number"
            style="@style/Widget.AppCompat.SeekBar.Discrete"
            android:max="10"
            android:visibility="visible"
            android:progress="4"
            android:thumb="@drawable/drw_thumb_seekbar"
            android:progressDrawable="@drawable/drw_bg_seekbar"
            android:tickMark="@drawable/drw_bg_tickmark"/>

</RelativeLayout>

您可以使用库轻松创建自定义搜索栏。 例如:我使用 this 库创建了一个非常相似的搜索栏。

要实施该库,只需将下面的代码添加到您的 build.gradle 文件中。

implementation 'com.github.warkiz.widget:indicatorseekbar:2.1.2'

然后在 yourLayout.xml 文件中创建搜索栏,如下所示:

<com.warkiz.widget.IndicatorSeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isb_max="100"
app:isb_min="-1.0"
app:isb_progress="25"
app:isb_seek_smoothly="true"
app:isb_ticks_count="5"
app:isb_show_tick_marks_type="oval"
app:isb_tick_marks_size="13dp"
app:isb_tick_marks_drawable="@mipmap/ic_launcher" //create your own drawable file and add it here
app:isb_show_tick_texts="true"
app:isb_tick_texts_size="15sp"
app:isb_tick_texts_color="@color/color_blue"
app:isb_thumb_color="@color/color_green"
app:isb_thumb_size="20dp"
app:isb_show_indicator="rounded_rectangle"
app:isb_indicator_color="@color/color_gray"
app:isb_indicator_text_color="@color/colorAccent"
app:isb_indicator_text_size="18sp"
app:isb_track_background_color="@color/color_gray"
app:isb_track_background_size="2dp"
app:isb_track_progress_color="@color/color_blue"
app:isb_track_progress_size="4dp"
app:isb_only_thumb_draggable="false"/>

根据需要调整搜索栏,一切顺利!

有关库的更多信息,请查看下面的 link:

IndicatorSeekBar

您可以扩展 AppCompatSeekBar,只需覆盖 onDraw() 方法,然后重绘所有内容:

我必须检查:

https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/widget/AbsSeekBar.java

弄清楚事物是如何绘制的。

所以,你需要画画

绘图顺序很重要:

  • 背景
  • 刻度线
  • 进度
  • 拇指

绘图顺序不重要:

注意:为了满足上面的绘制顺序,我不得不将SeekBar背景和Progress Drawables分开。

注意:我用android:background="@null"去除了拇指阴影(如果包含拇指阴影,它会显示错位):

Remove SeekBar shadow

CustomSeekBar class

public class CustomSeekBar extends AppCompatSeekBar {

/**
 * The value that the canvas is translated by in order to show progress values
 * This value is dependent on progress values text size
 */
private final int DY = 35;

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

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

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

@Override
protected synchronized void onDraw(Canvas canvas) {
    //super.onDraw(canvas);
    drawBackground(canvas);
    drawTickMarks(canvas);
    drawProgress(canvas);
    drawThumb(canvas);
    drawValues(canvas);
}


@TargetApi(Build.VERSION_CODES.N)
void drawBackground(Canvas canvas) {
    final Drawable b = ContextCompat.getDrawable(getContext(),
            R.drawable.drw_background_seekbar);
    Drawable mTickMark = getTickMark();
    if (b != null) {
        final int saveCount = canvas.save();
        canvas.translate(getPaddingLeft(), DY);
        Rect rectE = new Rect(-mTickMark.getBounds().width(), getHeight() / 4,
                getWidth() - 2*mTickMark.getBounds().width(), 3 * getHeight() / 4);
        b.setBounds(rectE);
        b.draw(canvas);
        canvas.restoreToCount(saveCount);
    }
}

@TargetApi(Build.VERSION_CODES.N)
void drawProgress(Canvas canvas) {
    final Drawable d = getProgressDrawable();
    Drawable mTickMark = getTickMark();
    if (d != null) {
        final int saveCount = canvas.save();
        canvas.translate(getPaddingLeft(), DY);
        Rect rectE = new Rect(-mTickMark.getBounds().width(), getHeight() / 4,
                getWidth() - 2 * mTickMark.getBounds().width(), 3 * getHeight() / 4);
        d.setBounds(rectE);
        d.draw(canvas);
        canvas.restoreToCount(saveCount);
    }
}

@TargetApi(Build.VERSION_CODES.N)
private void drawTickMarks(Canvas canvas) {
    Drawable mTickMark = getTickMark();
    if (mTickMark != null) {
        int count = getMax();
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            count = getMax() - getMin();
        }
        if (count > 1) {
            final int w = mTickMark.getIntrinsicWidth();
            final int h = mTickMark.getIntrinsicHeight();
            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()) / (float) count;
            final int saveCount = canvas.save();
            canvas.translate(getPaddingLeft(), getHeight() / 2);
            canvas.translate(0, DY);
            for (int i = 0; i <= count; i++) {
                mTickMark.draw(canvas);
                canvas.translate(spacing, 0);
            }
            canvas.restoreToCount(saveCount);
        }
    }
}

@TargetApi(Build.VERSION_CODES.N)
private void drawValues(Canvas canvas) {
    Drawable mTickMark = getTickMark();
    if (mTickMark != null) {
        int count = getMax();
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            count = getMax() - getMin();
        }
        if (count > 1) {
            final float spacing = (getWidth() - getPaddingLeft() - getPaddingRight()) / (float) count;
            final int saveCount = canvas.save();
            canvas.translate(getPaddingLeft(), getHeight() / 2 - DY);
            for (int i = 0; i <= count; i = i+2) {
                drawValue(canvas, String.valueOf(i));
                canvas.translate(2 * spacing, 0);
            }
            canvas.restoreToCount(saveCount);
        }
    }
}

private void drawValue(Canvas canvas, String text){
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setColor(Color.GRAY);
    paint.setStyle(Paint.Style.FILL);
    paint.setTextSize(35);
    paint.setTextAlign(Paint.Align.CENTER);
    canvas.drawText(text, 0, 0, paint);
}


/**
 * Draw the thumb.
 */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
void drawThumb(Canvas canvas) {
    Drawable mThumb = getThumb();
    if (mThumb != null) {
        final int saveCount = canvas.save();
        canvas.translate(getPaddingLeft() - getThumbOffset(), DY + getPaddingTop());
        mThumb.draw(canvas);
        canvas.restoreToCount(saveCount);
    }
}

}

Example:

MainActivityclass:

public class MainActivity extends AppCompatActivity {

private final String TAG = MainActivity.class.getSimpleName();
private AppCompatSeekBar seekbar;
private CustomSeekBar csb;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    seekbar = (AppCompatSeekBar) findViewById(R.id.seekbar);
    seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
            Snackbar.make(seekBar, "Progress " + i, Snackbar.LENGTH_INDEFINITE).show();
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });
    csb = (CustomSeekBar) findViewById(R.id.csb);
    csb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
            Snackbar.make(seekBar, "Custom Progress " + i, Snackbar.LENGTH_INDEFINITE).show();
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });

    }

main_activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">

<androidx.appcompat.widget.AppCompatSeekBar
    android:id="@+id/seekbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="15dp"
    android:layout_marginRight="15dp"
    android:layout_marginTop="100dp"
    android:max="10"
    android:visibility="visible"
    android:progress="4"
    android:splitTrack="false"
    android:tickMark="@drawable/drw_bg_tickmark"
    android:thumb="@drawable/drw_thumb_seekbar"
    android:progressDrawable="@drawable/drw_bg_seekbar"/>

<com.example.rabee.myapplication.CustomSeekBar
    android:id="@+id/csb"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:layout_marginLeft="15dp"
    android:layout_marginRight="15dp"
    android:layout_marginTop="10dp"
    android:layout_below="@id/seekbar"
    android:max="10"
    android:visibility="visible"
    android:progress="4"
    android:background="@null"
    android:tickMark="@drawable/drw_bg_tickmark"
    android:thumb="@drawable/drw_thumb_seekbar"
    android:progressDrawable="@drawable/drw_progress_seekbar"/>

</RelativeLayout>

drw_bg_seekbar.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@android:id/background"
    android:gravity="center_vertical">
    <shape android:shape="rectangle">
        <corners android:radius="15dp"/>
        <size android:height="30dp" />
        <solid android:color="#DCDCDC" />
    </shape>
</item>

<item android:id="@android:id/progress"
    android:gravity="center_vertical">
    <scale android:scaleWidth="100%">
        <selector>
            <item>
                <shape android:shape="rectangle"
                    >
                    <corners android:radius="15dp"/>
                    <size android:height="30dp" />
                    <solid android:color="@android:color/holo_green_light" />
                </shape>
            </item>
        </selector>
    </scale>
</item>

</layer-list>

drw_background_seekbar.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@android:id/background"
    android:gravity="center_vertical">
    <shape android:shape="rectangle">
        <corners android:radius="15dp"/>
        <size android:height="30dp" />
        <solid android:color="#DCDCDC" />
    </shape>
</item>

</layer-list>

drw_progress_seekbar.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

<item
    android:id="@android:id/progress"
    android:gravity="center_vertical">
                <scale android:scaleWidth="100%">
                <shape android:shape="rectangle">
                    <corners android:radius="15dp"/>
                    <size android:height="30dp" />
                    <solid android:color="@android:color/holo_green_light" />
                </shape>
                </scale>
            </item>

</layer-list>

drw_bg_tickmark.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:tint="#696969">
<corners android:radius="4dp"/>
<size android:width="10dp"
    android:height="10dp" />
<solid android:color="@android:color/darker_gray" />

drw_thumb_seekbar.xml:

<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
>
<solid
    android:color="#696969" />
<size
    android:width="40dp"
    android:height="40dp" />
</shape>

Output: