Android с SeekBar - предотвращение движения большого пальца при касании SeekBar для перетаскивания / прокрутки экрана - PullRequest
4 голосов
/ 24 апреля 2011

У меня есть приложение для Android с TableLayout, в каждой строке которого есть SeekBar и ToggleButton. Строки выходят за пределы видимого диапазона экрана, поэтому его можно прокручивать. Когда я касаюсь и перетаскиваю, чтобы прокрутить страницу вверх, и в процессе касаюсь SeekBar, он немедленно меняет положение «большого пальца» вместо прокрутки страницы. Однако ToggleButton не ведет себя так; вместо этого я могу начать перетаскивание на кнопку и прокрутить, а затем отпустить без изменения состояния ToggleButton.

Есть ли способ заставить SeekBar вести себя таким образом, чтобы прикосновение к нему для начала перетаскивания не приводило к изменению позиций панели, а к прокрутке страницы?

Ответы [ 2 ]

3 голосов
/ 27 апреля 2012

У меня были похожие проблемы. Единственное решение, которое я смог найти (когда панель поиска находится в виде списка), - отключить панель поиска до тех пор, пока не будет нажат элемент.

Решение

В ArrayAdapter я установил для обоих включенных и фокусируемых значение false и добавил прослушиватель SeekBar, установив атрибуты в false, что позволило мне использовать элемент списка в прослушивателеIIClicked. Внутри onItemCLickListener я получил панель поиска, установив атрибуты в true, это означало, что ее можно перемещать вверх или вниз. Затем я отключил его после того, как была произведена корректировка. код ниже

Фрагмент ArrayAdapter

этот код находится внутри создания элемента списка, в котором находится панель поиска

    seekBar.setClickable(false);
    seekBar.setFocusable(false);
    seekBar.setEnabled(false);

    /* attach listener */
    attachProgressUpdatedListener(seekBar, positionOfItemInList);

AttachProgressUpdatedListener

этот метод присоединяет слушателя к панели поиска внутри класса arrayAdapter

private void attachProgressUpdatedListener(SeekBar seekBar,
    final int position) {

seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

    public void onStopTrackingTouch(SeekBar seekBar) {
    int progress = seekBar.getProgress();
    int task_id = (Integer) seekBar.getTag();

    TaskHandler taskHandler = new TaskHandler(DBAdapter
        .getDBAdapterInstance(getContext()));

    taskHandler.updateTaskProgress(task_id, progress);

    mList.get(position).setProgress(progress);

    //need to fire an update to the activity
    notifyDataSetChanged();
    seekBar.setEnabled(false);

    }

    public void onStartTrackingTouch(SeekBar seekBar) {
    // empty as onStartTrackingTouch listener not being used in
    // current implementation

    }

    public void onProgressChanged(SeekBar seekBar, int progress,
        boolean fromUser) {
    // empty as onProgressChanged listener not being used in
    // current implementation

    }
});

}

OnItemCLickListener

это отрывок из действия, в котором находится представление списка.

taskListView.setOnItemClickListener(new OnItemClickListener() {
    public void onItemClick(AdapterView<?> parent, View view,
        int position, long id) {
    SeekBar sb = (SeekBar) view.findViewById(R.id.seek);
    sb.setFocusable(true);
    sb.setEnabled(true);

    }
});
0 голосов
/ 28 сентября 2011

Я получил его, подклассифицировав панель поиска и проверив, больше ли угол движения, чем 45 градусов.В этом случае игнорируйте касания и возвращайте false, чтобы представление прокрутки сделало свое дело.

Edit:

Вот расширенный 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;
    }

}

seekbarex.xml ниже.Это просто, чтобы добавить мин / макс / значение как плавающие.

<declare-styleable name="SeekBarEx">

<attr name="min" format="float"/>
<attr name="max" format="float"/>
<attr name="value" format="float"/>
</declare-styleable>

</resources>
...