SeekBar 自定义 样式 详解

SeekBar 自定义 样式 详解

 

SeekBar简介

SeekBar是ProgressBar的扩展,添加了可拖动的滑块。

我们使用进度条时,可以使用系统默认的进度条;

也可以自定义进度条的图片和滑块图片等。

用户可以触摸拇指并向左或向右拖动以设置当前进度级别,或使用箭头键。

不建议将可聚焦的小部件放置在SeekBar的左侧或右侧。

 

自定义效果:

 

 

<SeekBar
            android:id="@+id/sb_screen_bri"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:progress="66"
            android:progressDrawable="@drawable/poc_seek_bar_drawable"
            android:splitTrack="false"
            android:thumbTint="@android:color/transparent" />

 

<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2018 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@android:id/background"
        android:gravity="center_vertical|fill_horizontal">
        <shape android:shape="rectangle">
            <size android:height="10dp" />
            <solid android:color="#282b31" />
            <corners android:radius="10dp" />
        </shape>
    </item>
    <item
        android:id="@android:id/progress"
        android:gravity="center_vertical|fill_horizontal">
        <scale android:scaleWidth="100%">
            <shape android:shape="rectangle">
                <size android:height="10dp" />
                <!--<solid android:color="#707d93" />-->
                <gradient
                    android:angle="0"
                    android:endColor="#aab8d4"
                    android:startColor="#707d93" />
                <corners android:radius="10dp" />
            </shape>
        </scale>
    </item>
</layer-list>

 

 结构分析:

SeekBar的结构分析图

属性:

android:maxHeight   // 背景高度
android:progressDrawable  // 进度条背景
android:thumb  // 滑块
android:splitTrack //  hua块 是否切割 seekbar 背景,默认true,会看到thumb周围区域被切割

 

seekbar扩展:


1、滑块不能位于进度条的最左边


解决方案: 设置偏移量

android:thumbOffset="5dp"

 

2、滑块不能居中在进度条中


解决方案:设置高度自适应,会自动契合滑块高度

android:layout_height="wrap_content"

然后使用以下属性设置高度

android:maxHeight="30dip"
android:minHeight="30dip" 

3、如何在滑块上写字


解决方案:重写ondraw方法

protected synchronized void onDraw(Canvas canvas) {  
        super.onDraw(canvas);  
        Rect rect = new Rect();  
        this.mPaint.getTextBounds(this.text, 0, this.text.length(), rect);  
        int x = (getWidth() / 2) - rect.centerX();  
        int y = (getHeight() / 2) - rect.centerY();  
        canvas.drawText(this.text, x, y, this.mPaint);  
    }   

  
在seekbar上面覆盖一个TextView
 

<?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="wrap_content"
    android:padding="16dp">

    <SeekBar
        android:id="@+id/sb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="0"
        android:progressDrawable="@drawable/seekbar_bg"
        android:thumb="@drawable/thumb"
        android:thumbOffset="0dp" />

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:text="请按住滑块,拖动到最右边"
        android:textColor="#888888"
        android:textSize="14dp" />
</RelativeLayout>

 
4、seekbar 中 thumb 出现的不透明效果


问题描述:
在Android5.0以上会出现thumb周围有一圈白色的不明东西,遮挡到父布局

解决方案:
设置splitTrack属性为false就可以了

android:splitTrack="false"

5、seekbar距离左右会有一定的边距


解决方案
设置seekbar的paddingleft与paddingright为0dp

 android:paddingStart="0dp"
 android:paddingEnd="0dp"  

 


6、禁止seekbar点击跳转进度,只能拖拽


解决思路

保存一个旧的位置progress——oldsign,默认是0,用户点击seekbar后方的时候,记录用户点击的progress

通过判断当前点击的progress是否 < (oldsign+某个值),

如果是则能拖动,如果否则设置seekbar位置progress为0,从而达到不动效果。

 

解决方案一:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class ValidateSeekBar extends SeekBar implements OnSeekBarChangeListener{

    private Context context;
    //记录旧的位置
    private int oldsign;
    //写进度条上text的画笔
    private Paint mPaint; 

    private String textStr ="请拖动到最右边完成验证";
    //text内容
    private String text=textStr;
    //text字体大小
    private int textSize =20;
    //text颜色
    private String textColor ="#607B8B";


    public interface ValidateSeekBarCallBack {
        void onProgressChangedCallBack(SeekBar seekbar, int progress, boolean arg2);
        void onStartTrackingTouchCallBack(SeekBar seekbar);
        void onStopTrackingTouchCallBack(SeekBar seekbar);
    }
    private ValidateSeekBarCallBack callback;

    public ValidateSeekBar(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public ValidateSeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
        init();
    }

    public ValidateSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    private void init() {
        this.mPaint = new Paint();  
        this.mPaint.setColor(Color.parseColor(textColor)); 
        this.mPaint.setTextSize(textSize);
        setMax(100);
        setOnSeekBarChangeListener(this);
    }

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

        Rect rect = new Rect();  
        this.mPaint.getTextBounds(this.text, 0, this.text.length(), rect);  
        int x = (getWidth() / 2) - rect.centerX();  
        int y = (getHeight() / 2) - rect.centerY();  
        canvas.drawText(this.text, x, y, this.mPaint);  
    }

    @Override
    public void onProgressChanged(SeekBar seekbar, int progress, boolean arg2) {
        //控制textview会闪的bug

        if(progress<(seekbar.getMax()/9+1)&&progress!=0){
            text="";
        }

        //当点击的位置大于 (0 + 100/9+1)时就不能被拖动  ,+号后数字越大,允许前方开始拖拽的范围就会越大
        //为什么要用“/”+某数值?是因为防止进度条的最大值有可能是1000、500、300等,所以都取进度条的 9分之1 + 一个自定义数值
        //为什么不能将判断改为当前位置大于 0? 因为在点击滑块的时候,progerss已经改变
        if(progress>oldsign+(seekbar.getMax()/9+1)){

            seekbar.setProgress(oldsign);
            return;
        }
        seekbar.setProgress(progress);
        oldsign = progress;
        if(this.callback!=null){
            this.callback.onProgressChangedCallBack(seekbar,progress,arg2);
        }

    }

    @Override
    public void onStartTrackingTouch(SeekBar seekbar) {

        seekbar.setProgress(oldsign);
        if(this.callback!=null){
            this.callback.onStartTrackingTouchCallBack(seekbar);
        }
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekbar) {

        if(seekbar.getProgress()!=seekbar.getMax()){
            oldsign=0;
            text =textStr;
            seekbar.setProgress(oldsign);
        }
        else{
            text ="完成验证";
        }


        if(this.callback!=null){
                this.callback.onStopTrackingTouchCallBack(seekbar);

            }

    }  
    /**
     * seekbar回调
     * @param callback
     */
    public void setValidateSeekBarCallBack(ValidateSeekBarCallBack callback){
        this.callback =callback;
    }

    public void refreshText(){
        text=textStr;
    }

}


此方案,因为前方可拖动的范围太难掌控,导致如果只是点击滑块按钮的附近位置的时候,滑块就会动,只有在可拖拉范围外才不会动。如果点击中间进行滑动,progress还会跟着滑动

 

解决方案二:可以解决从中间进行拖拽出现的问题

public class MainSeekbar extends android.support.v7.widget.AppCompatSeekBar implements SeekBar.OnSeekBarChangeListener {

    private static final int INDEX = 100;
    private static final int FINISH = 100;
    private boolean isMove = true;
    private OnSeekBarListener mOnSeekBarListener;

    public MainSeekbar(Context context) {
        super(context);
        setOnSeekBarChangeListener(this);
    }

    public MainSeekbar(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOnSeekBarChangeListener(this);
    }

    public MainSeekbar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOnSeekBarChangeListener(this);
    }

    public void setOnSeekBarListener(OnSeekBarListener onSeekBarListener) {
        mOnSeekBarListener = onSeekBarListener;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            isMove = true;
            if (x - INDEX > 0) {
                isMove = false;
                return true;
            }
        }
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            if (!isMove) {
                return true;
            }
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        if (seekBar.getProgress() != FINISH || !isMove) {
            seekBar.setProgress(0);
            mOnSeekBarListener.onStart();
        } else {
            mOnSeekBarListener.onFinish();
        }
    }


    protected interface OnSeekBarListener {
        void onFinish();
        void onStart();
    }
}

OVER ~! 仅供参考~!

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 10
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SeekBar是Android中的一个自定义控件,它允许用户通过滑动来选择一个数值。你可以在XML布局文件中声明一个SeekBar控件,并通过代码来获取和设置其值。 要创建一个自定义SeekBar控件,你可以继承SeekBar类,并重写一些方法来实现自定义的行为。以下是一个示例: ```java public class CustomSeekBar extends SeekBar { 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 public synchronized void setProgress(int progress) { // 在设置进度之前进行一些自定义操作 // 例如限制进度的范围或者改变进度条的外观 super.setProgress(progress); } @Override public synchronized void onProgressChanged(int progress, boolean fromUser) { super.onProgressChanged(progress, fromUser); // 当进度发生改变时的处理逻辑 // 可以根据进度值做出相应的响应 } } ``` 在这个示例中,我们重写了`setProgress()`方法和`onProgressChanged()`方法来实现自定义行为。你可以根据自己的需求进行修改和扩展。 在布局文件中使用自定义SeekBar控件时,需要指定完整的自定义控件的类名,例如: ```xml <com.example.app.CustomSeekBar android:id="@+id/customSeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" /> ``` 这样就可以在代码中获取到这个自定义SeekBar控件,并对其进行操作了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值