Android和SeekBar-Prevent';拇指';从触摸SeekBar时移动到拖动/滚动屏幕
我有一个android应用程序,它有一个表格布局,每一行都有一个SeekBar和一个ToggleButton。这些行超出了屏幕的可见范围,因此可以滚动。当我触摸并拖动页面向上滚动,并在此过程中触摸SeekBar时,它会立即改变“拇指”的位置,而不是滚动页面。但是,ToggleButton的行为不是这样的;相反,我可以开始拖动按钮并滚动,然后释放,而无需切换按钮更改状态Android和SeekBar-Prevent';拇指';从触摸SeekBar时移动到拖动/滚动屏幕,android,seekbar,Android,Seekbar,我有一个android应用程序,它有一个表格布局,每一行都有一个SeekBar和一个ToggleButton。这些行超出了屏幕的可见范围,因此可以滚动。当我触摸并拖动页面向上滚动,并在此过程中触摸SeekBar时,它会立即改变“拇指”的位置,而不是滚动页面。但是,ToggleButton的行为不是这样的;相反,我可以开始拖动按钮并滚动,然后释放,而无需切换按钮更改状态 <declare-styleable name="SeekBarEx"> <attr name="min"
<declare-styleable name="SeekBarEx">
<attr name="min" format="float"/>
<attr name="max" format="float"/>
<attr name="value" format="float"/>
</declare-styleable>
</resources>
有没有办法让SeekBar以这种方式运行,这样触摸它开始拖动不会导致工具栏改变位置,而是滚动页面?我通过对SeekBar进行子类化并检查运动角度是否大于45度来实现它。在这种情况下,忽略触摸并返回false,这样滚动视图就可以完成它的工作
<declare-styleable name="SeekBarEx">
<attr name="min" format="float"/>
<attr name="max" format="float"/>
<attr name="value" format="float"/>
</declare-styleable>
</resources>
编辑:
<declare-styleable name="SeekBarEx">
<attr name="min" format="float"/>
<attr name="max" format="float"/>
<attr name="value" format="float"/>
</declare-styleable>
</resources>
这是一个扩展的SeekBar,允许您在浮点而不是整数中设置最小/最大值
public class SeekBarEx extends SeekBar implements
SeekBar.OnSeekBarChangeListener {
final int SEEK_POINTS = 0x10000;
final String TAG = "SeekBarEx";
public float mMax;
public float mMin;
public OnSeekBarExChangeListener delegate = null;
public interface OnSeekBarExChangeListener {
public void onSeekChanged(SeekBarEx seekBarEx, float value,
boolean fromUser);
public void onStartTrackingTouch(SeekBarEx seekBar);
public void onStopTrackingTouch(SeekBarEx seekBar);
}
public SeekBarEx(Context ctx, AttributeSet attr) {
super(ctx, attr);
super.setMax(SEEK_POINTS);
mMin = 0f;
mMax = 1.0f;
initAttributes(attr);
this.setOnSeekBarChangeListener(this);
}
public void setDelegate(OnSeekBarExChangeListener d) {
delegate = d;
}
public void initAttributes(AttributeSet attrSet) {
TypedArray a;
a = getContext().obtainStyledAttributes(attrSet, R.styleable.SeekBarEx);
final int N = a.getIndexCount();
int i;
for (i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.SeekBarEx_max:
mMax = a.getFloat(i, 1.0f);
Log.d(TAG, "maxSet " + mMax);
break;
case R.styleable.SeekBarEx_min:
mMin = a.getFloat(i, 0f);
Log.d(TAG, "minSet" + mMin);
break;
case R.styleable.SeekBarEx_value:
this.setValue(a.getFloat(i, 0));
break;
}
}
a.recycle();
}
@Override
public int getProgress() {
return super.getProgress();
}
public float getValue() {
float r;
float run;
r = (float) super.getProgress();
r = r / (float) SEEK_POINTS;
run = mMax - mMin;
r = r * run + mMin;
return r;
}
public void setValue(float v) {
if (Float.isNaN(v) || Float.isInfinite(v))
return;
if (v > mMax)
v = mMax;
if (v < mMin)
v = mMin;
float run;
int setv;
run = mMax - mMin;
v -= mMin;
setv = Math.round(v * (float) SEEK_POINTS / run);
super.setProgress(setv);
}
public boolean valueChanged = false;
public void cancelTracking() {
if (oldValue != Float.NaN) {
this.setValue(oldValue);
oldValue = Float.NaN;
valueChanged = false;
acceptTouches = false;
acceptChange = false;
}
}
// we override these methods so that when we forcully cancel
// on ontouches moved. We can revert back to the old value
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
Log.d(TAG, "SeekBar changed to " + progress);
if (delegate != null && acceptTouches) {
valueChanged = true;
delegate.onSeekChanged(this, this.getValue(), fromUser);
} else
cancelTracking();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
if (delegate != null)
delegate.onStartTrackingTouch(this);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (delegate != null && valueChanged)
delegate.onStopTrackingTouch(this);
else
cancelTracking();
acceptChange = false;
valueChanged = false;
}
public float mY, mX;
public boolean acceptTouches = true;
// acceptChange never read todo: delete
public boolean acceptChange = false;
public float oldValue = Float.NaN;
public ScrollView getScrollView() {
View view;
view = this;
int maxUp;
maxUp = 5;
while (view != null && maxUp > 0) {
view = (View) view.getParent();
ScrollView scroller;
if (view instanceof ScrollView) {
scroller = (ScrollView) view;
return scroller;
}
maxUp--;
}
return null;
}
// **************************************
// This is the important part in achieving the effect in scroll
// view to be nice
@Override
public boolean onTouchEvent(MotionEvent event) {
int action;
action = event.getAction() & MotionEvent.ACTION_MASK;
ScrollView scroller = this.getScrollView();
boolean mayScroll;
mayScroll = true;
if (scroller == null)
mayScroll = false;
else {
int scrollAmount = scroller.getMaxScrollAmount();
if (scrollAmount == 0)
mayScroll = false;
}
switch (action) {
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "got cancel touches");
cancelTracking();
super.onTouchEvent(event);
return true;
case MotionEvent.ACTION_DOWN:
mX = event.getX();
mY = event.getY();
acceptTouches = true;
acceptChange = false;
oldValue = this.getValue();
valueChanged = false;
break;
case MotionEvent.ACTION_MOVE:
float x;
float y;
x = event.getX();
y = event.getY();
float dx;
float dy;
dx = x - mX;
dy = y - mY;
if (dx < 0)
dx = -dx;
if (dy < 0)
dy = -dy;
y = this.getHeight() / 2 - y;
float angle;
float distance;
distance = dx * dx + dy * dy;
// I just realized this is wrong it should be
// angle = (float)Math.acos(Math.abs(dx)/Math.sqrt(distance))
// I'm leaving it until tested or someone can confirm
angle = (float) Math.atan(dy / dx);
int distanceLimit;
distanceLimit = this.getHeight() / 3;
distanceLimit *= distanceLimit;
// if we move at an angle of atleast 45degrees
// cancel
if (mayScroll && angle > Math.PI / 4.0) {
cancelTracking();
}
mX += 100000;
if (y < 0)
y = -y;
// if we moved finger too far just cancel
// cause the person may have wanted to scroll but
// failed so we revert back to the old value
if (y > this.getHeight() * 2) {
cancelTracking();
} else if (acceptTouches)
acceptChange = true;
break;
default:
break;
}
// if we accept touches do the usual otherwise
// return false so scrollView can do it's thing
if (acceptTouches)
return super.onTouchEvent(event);
return false;
}
}
<declare-styleable name="SeekBarEx">
<attr name="min" format="float"/>
<attr name="max" format="float"/>
<attr name="value" format="float"/>
</declare-styleable>
</resources>
public类SeekBarEx扩展SeekBar实现
SeekBar.onseekbarchaneglistener{
最终整数搜索点=0x10000;
最后一个字符串标记=“SeekBarEx”;
公共浮动mMax;
公众浮点数;
public OnSeekBarExChangeListener委托=null;
SeekbareXchangeListener上的公共接口{
SeekChanged上的公共无效(SeekBarEx SeekBarEx,浮动值,
布尔值(用户);
开始跟踪触摸时的公共无效(SeekBarEx seekBar);
TopTrackingTouch(SeekBarEx seekBar)上的公共无效;
}
公共SeekBarEx(上下文ctx,属性集attr){
超级(ctx、attr);
super.setMax(搜索点);
mMin=0f;
mMax=1.0f;
初始属性(attr);
this.setonseekbarchaneglistener(this);
}
public void setDelegate(onseekbarexchanged侦听器){
代表=d;
}
public void initAttributes(AttributeSet attreset){
Darray a型;
a=getContext().ActainStyledAttributes(attrSet,R.styleable.SeekBarEx);
final int N=a.getIndexCount();
int i;
对于(i=0;imMax)
v=mMax;
if(v0){
view=(view)view.getParent();
滚动视图滚动条;
如果(滚动视图的视图实例){
滚动器=(滚动视图)视图;
返回滚动条;
}
马克斯普--;
}
返回null;
}
// **************************************
//这是实现滚动效果的重要部分
//景色宜人
@凌驾
公共布尔onTouchEvent(运动事件){
内联作用;
action=event.getAction()&MotionEvent.action\u掩码;
ScrollView scroller=this.getScrollView();
布尔卷轴;
maycoll=true;
如果(滚动条==null)
maycoll=false;
否则{
int scrollmount=scroller.getMaxScrollmount();
如果(滚动量==0)
maycoll=false;
}
开关(动作){
case MotionEvent.ACTION\u取消:
Log.d(标记“got cancel t