【问题标题】:Detecting thumb position in SeekBar prior to API version 16在 API 版本 16 之前检测 SeekBar 中的拇指位置
【发布时间】:2013-09-08 10:47:00
【问题描述】:

基本上,我需要检测 SeekBar 中的进度何时发生变化,并在拇指顶部绘制一个文本视图,指示进度值。

我通过实现OnSeekBarChangeListener 来做到这一点 在public void onProgressChanged(SeekBar seekBar, int progress, boolean b) 方法上,我调用Rect thumbRect = seekBar.getThumb().getBounds(); 来确定拇指的位置。

这工作得很好,但显然getThumb() 仅在 API 级别 16+ (Android 4.1) 中可用,导致早期版本出现 NoSuchMethodError

知道如何解决这个问题吗?

【问题讨论】:

    标签: android android-layout seekbar android-compatibility


    【解决方案1】:

    我能够使用我自己的类来获取 Thumb:

    MySeekBar.java

    package mobi.sherif.seekbarthumbposition;
    
    import android.content.Context;
    import android.graphics.drawable.Drawable;
    import android.util.AttributeSet;
    import android.widget.SeekBar;
    
    public class MySeekBar extends SeekBar {
    
        public MySeekBar(Context context) {
            super(context);
        }
        public MySeekBar(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        public MySeekBar(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        Drawable mThumb;
        @Override
        public void setThumb(Drawable thumb) {
            super.setThumb(thumb);
            mThumb = thumb;
        }
        public Drawable getSeekBarThumb() {
            return mThumb;
        }
    
    }
    

    在活动中,这非常有效:

    package mobi.sherif.seekbarthumbposition;
    
    import android.app.Activity;
    import android.graphics.Rect;
    import android.os.Bundle;
    import android.util.Log;
    import android.widget.SeekBar;
    import android.widget.SeekBar.OnSeekBarChangeListener;
    
    public class MainActivity extends Activity implements OnSeekBarChangeListener {
        MySeekBar mSeekBar;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mSeekBar = (MySeekBar) findViewById(R.id.seekbar);
            mSeekBar.setOnSeekBarChangeListener(this);
        }
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
            Rect thumbRect = mSeekBar.getSeekBarThumb().getBounds();
            Log.v("sherif", "(" + thumbRect.left + ", " + thumbRect.top + ", " + thumbRect.right + ", " + thumbRect.bottom + ")");
        }
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            // TODO Auto-generated method stub
    
        }
    }
    

    【讨论】:

    • 完美运行,谢谢! (我需要等待 20 小时才能将赏金发送给您)
    • 等待 7 天,以防有人给出更好的答案。虽然我讨厌使用反射,但可以通过反射获得可绘制对象。有机会发布更多答案。
    【解决方案2】:

    希望这可以为其他人节省一些时间!

    我创建了这个方法而不是自定义 seekBar:

    public int getSeekBarThumbPosX(SeekBar seekBar) {
        int posX;
        if (Build.VERSION.SDK_INT >= 16) {
            posX = seekBar.getThumb().getBounds().centerX();
        } else {
            int left = seekBar.getLeft() + seekBar.getPaddingLeft();
            int right = seekBar.getRight() - seekBar.getPaddingRight();
            float width = (float) (seekBar.getProgress() * (right - left)) / seekBar.getMax();
            posX = Math.round(width) + seekBar.getThumbOffset();
        }
        return posX;
    }
    

    【讨论】:

      【解决方案3】:

      一个绝妙的解决方案!谢谢。 只需添加即可使用自定义搜索栏,您需要修改您的 xml

       <com.example.MySeekBar
            android:id="@+id/..."
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_weight="1"
            android:minHeight="3dp"
            android:maxHeight="3dp"
            android:progressDrawable="@drawable/seek_bar_2"
            android:thumb="@drawable/thumbler_seekbart_circle"
            android:thumbOffset="8dp" />
      

      android:thumbOffset="8dp" - 是拇指的一半,最好指定,因此文本中心和拇指不会不匹配

      定位可以是这样的:

      int possition = (int) (seekBar.getX() //the beginning of the seekbar
      + seekBar.getThumbOffset() / 2        //the half of our thumb - the text to be above it's centre
      + ((MySeekBar) seekBar).getSeekBarThumb().getBounds().exactCenterX()); //position of a thumb inside the seek bar
      

      【讨论】:

        【解决方案4】:

        @Sherif elKhatib 的回答很棒,但缺点是即使在 API>=16 上也缓存拇指副本。 我对其进行了改进,使其仅在 APIDrawable,并且它覆盖了 SeekBar.java 中的方法,以避免两个方法在 API>=16 上执行相同的操作。唯一的缺点:它需要目标 SDK >= 16,这应该是当今大多数应用程序的情况。

        public class ThumbSeekBar extends AppCompatSeekBar {
        
            private Drawable thumb;
        
            public ThumbSeekBar(Context context) {
                super(context);
            }
        
            public ThumbSeekBar(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
        
            public ThumbSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
                super(context, attrs, defStyleAttr);
            }
        
            @Override
            public Drawable getThumb() {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    return super.getThumb();
                }
                return thumb;
            }
        
            @Override
            public void setThumb(Drawable thumb) {
                super.setThumb(thumb);
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                    this.thumb = thumb;
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2012-12-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多