在 Android 中实现一个滑块(SeekBar)

Posted

技术标签:

【中文标题】在 Android 中实现一个滑块(SeekBar)【英文标题】:Implementing a slider (SeekBar) in Android 【发布时间】:2012-01-27 14:37:16 【问题描述】:

我想实现一个滑块,它基本上是两条线,一条垂直,一条水平,穿过屏幕被触摸的地方。我已经成功制作了一个,但我必须解决问题:

    滑块不是很流畅,移动手指时有一点延迟 如果我放置两个滑块,则不是多点触控,我想同时使用它们

代码如下:

public class Slider extends View 

    private Controller controller = new Controller();
    private boolean initialisedSlider;
    private int sliderWidth, sliderHeight;
    private Point pointStart;
    private Paint white;
    private int mode;

    final static int VERTICAL = 0, HORIZONTAL = 1, BOTH = 2;

    public Slider(Context context) 
        super(context);
        setFocusable(true);    
        // TODO Auto-generated constructor stub
    
    public Slider(Context context, AttributeSet attrs) 
        super(context, attrs);     
        setFocusable(true);    
        pointStart = new Point();
        initialisedSlider = false;   
        mode = Slider.BOTH;
    

    @Override
    protected void onDraw(Canvas canvas) 
        if(!initialisedSlider) 
            initialisedSlider = true;
            sliderWidth = getMeasuredWidth();
            sliderHeight = getMeasuredHeight();

            pointStart.x = (int)(sliderWidth/2.0);
            pointStart.y = (int)(sliderHeight/2.0);
            controller = new Controller(pointStart, 3);

            white = new Paint();
            white.setColor(0xFFFFFFFF);
        

        canvas.drawLine(controller.getCoordX(),0,
                        controller.getCoordX(),sliderHeight, 
                        white);
        canvas.drawLine(0, controller.getCoordY(), 
                        sliderWidth, controller.getCoordY(), 
                        white);

    

    public boolean onTouchEvent(MotionEvent event) 
        int eventaction = event.getAction();     
        int X = (int)event.getX(); 
        int Y = (int)event.getY(); 
        switch (eventaction)  
        case MotionEvent.ACTION_DOWN:
            if(isInBounds(X,Y)) 
                updateController(X, Y);
            
            break;
        case MotionEvent.ACTION_MOVE:
            if(isInBounds(X,Y)) 
                updateController(X, Y);
            
            break;
        case MotionEvent.ACTION_UP:
            if(isInBounds(X,Y)) 
                updateController(X, Y);
            
            break;
        
        invalidate();  
        return true; 
    

    private boolean isInBounds(int x, int y) 
        return ((x<=(sliderWidth)) && (x>=(0)) 
                 && (y<=(sliderHeight)) && (y>=(0)));
    
    private void updateController(int x, int y) 
        switch(mode) 
        case Slider.HORIZONTAL:
            controller.setCoordX(x);
            break;
        case Slider.VERTICAL:
            controller.setCoordY(y);
            break;
        case Slider.BOTH:
            controller.setCoordX(x);
            controller.setCoordY(y);
            break;
        
    

    private class Controller 
        private int coordX, coordY;
        Controller() 

        
        Controller(Point point, int width) 
            setCoordX(point.x);
            setCoordY(point.y);
        
        public void setCoordX(int coordX) 
            this.coordX = coordX;
        
        public int getCoordX() 
            return coordX;
        
        public void setCoordY(int coordY) 
            this.coordY = coordY;
        
        public int getCoordY() 
            return coordY;
        
    

以及 XML 文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:orientation="vertical" >

    <TextView
        android:layout_
        android:layout_
        android:text="@string/hello" />
    <com.android.lasttest.Slider 
        android:id="@+id/slider"
        android:layout_ 
        android:layout_ 
        android:layout_gravity="center_horizontal" 
        android:adjustViewBounds="true"/>
    <com.android.lasttest.Slider 
        android:id="@+id/slider"
        android:layout_ 
        android:layout_ 
        android:layout_gravity="center_horizontal" 
        android:adjustViewBounds="true"/>
    <com.android.lasttest.Slider 
        android:id="@+id/slider"
        android:layout_ 
        android:layout_ 
        android:layout_gravity="center_horizontal" 
        android:adjustViewBounds="true"/>

</LinearLayout>

【问题讨论】:

【参考方案1】:

如何实现 SeekBar

将 SeekBar 添加到您的布局中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_
    android:layout_>

    <TextView
        android:id="@+id/textView"
        android:layout_margin="20dp"
        android:layout_
        android:layout_/>

    <SeekBar
        android:id="@+id/seekBar"
        android:max="100"
        android:progress="50"
        android:layout_
        android:layout_/>

</LinearLayout>

注意事项

max 是搜索栏可以达到的最高值。默认值为100。最小值为0。 xml min 值仅适用于 API 26,但您可以通过编程将 0-100 范围转换为早期版本所需的任何值。 progress 是滑块点(称为“拇指”)的初始位置。 对于垂直 SeekBar,请使用 android:rotation="270"

监听代码变化

public class MainActivity extends AppCompatActivity 

    TextView tvProgressLabel;

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

        // set a change listener on the SeekBar
        SeekBar seekBar = findViewById(R.id.seekBar);
        seekBar.setOnSeekBarChangeListener(seekBarChangeListener);

        int progress = seekBar.getProgress();
        tvProgressLabel = findViewById(R.id.textView);
        tvProgressLabel.setText("Progress: " + progress);
    

    SeekBar.OnSeekBarChangeListener seekBarChangeListener = new SeekBar.OnSeekBarChangeListener() 

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) 
            // updated continuously as the user slides the thumb
            tvProgressLabel.setText("Progress: " + progress);
        

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) 
            // called when the user first touches the SeekBar
        

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) 
            // called after the user finishes moving the SeekBar
        
    ;

注意事项

如果您在用户移动搜索栏时不需要进行任何更新,那么您可以在onStopTrackingTouch 中更新 UI。

另见

SeekBar Tutorial With Example In Android Studio

【讨论】:

关于垂直搜索栏的说明。如果您想避免尺寸问题,请查看以下答案:***.com/a/51728247/6423246【参考方案2】:

Android 提供水平滑块

http://developer.android.com/reference/android/widget/SeekBar.html

并实现 OnSeekBarChangeListener

http://developer.android.com/reference/android/widget/SeekBar.OnSeekBarChangeListener.html

如果您想要垂直搜索栏,请点击此链接

http://hoodaandroid.blogspot.in/2012/10/vertical-seek-bar-or-slider-in-android.html

【讨论】:

【参考方案3】:

给未来的读者!

从material components android 1.2.0-alpha01开始,你有slider组件

例如:

<com.google.android.material.slider.Slider
        android:id="@+id/slider"
        android:layout_
        android:layout_
        android:valueFrom="20f"
        android:valueTo="70f"
        android:stepSize="10" />

Release notes Material Design Spec Docs

【讨论】:

以上是关于在 Android 中实现一个滑块(SeekBar)的主要内容,如果未能解决你的问题,请参考以下文章

Android 中的滑块控件... SeekBar 真的是我最好/唯一的选择吗?

seekBar拖动滑块

androd中怎么替换android seekbar 刻度的系统滑块图标

美化我们的seekbar

Xamarin.forms中的垂直滑块?

Android SeekBar 自定义