Android: скроллер анимации? - PullRequest
12 голосов
/ 31 марта 2011

Я новичок в разработке для Android, и я просто хотел бы немного узнать о виджете Scroller (android.widget.Scroller). Как это оживляет вид? Можно ли получить доступ к объекту Animation, если он существует? Если так, то как? Я прочитал исходный код, но не смог найти никаких подсказок, или, может быть, я слишком новый?

Я просто хотел выполнить некоторые операции после того, как Скроллер завершит прокрутку, что-то вроде

m_scroller.getAnimation().setAnimationListener(...);

Ответы [ 4 ]

38 голосов
/ 02 июня 2011

Виджет Scroller на самом деле не выполняет большую часть работы за вас. Он не вызывает никаких обратных вызовов, он ничего не оживляет, он просто реагирует на различные вызовы методов.

Так что же хорошего? Ну, он делает все вычисления, например, для тебя, что удобно. Итак, что вы обычно делаете, это создаете Runnable, который постоянно спрашивает Scroller: «Какой должна быть моя позиция прокрутки сейчас? Мы уже закончили бросать?» Затем вы репостируете этот исполняемый файл в обработчике (обычно в представлении) до тех пор, пока не завершите проверку.

Вот пример из фрагмента, над которым я сейчас работаю:

private class Flinger implements Runnable {
    private final Scroller scroller;

    private int lastX = 0;

    Flinger() {
        scroller = new Scroller(getActivity());
    }

    void start(int initialVelocity) {
        int initialX = scrollingView.getScrollX();
        int maxX = Integer.MAX_VALUE; // or some appropriate max value in your code
        scroller.fling(initialX, 0, initialVelocity, 0, 0, maxX, 0, 10);
        Log.i(TAG, "starting fling at " + initialX + ", velocity is " + initialVelocity + "");

        lastX = initialX;
        getView().post(this);
    }

    public void run() {
        if (scroller.isFinished()) {
            Log.i(TAG, "scroller is finished, done with fling");
            return;
        }

        boolean more = scroller.computeScrollOffset();
        int x = scroller.getCurrX();
        int diff = lastX - x;
        if (diff != 0) {
            scrollingView.scrollBy(diff, 0);
            lastX = x;
        }

        if (more) {
            getView().post(this);
        }
    }

    boolean isFlinging() {
        return !scroller.isFinished();
    }

    void forceFinished() {
        if (!scroller.isFinished()) {
            scroller.forceFinished(true);
        }
    }
}

Детали использования Scroller.startScroll должны быть похожими.

4 голосов
/ 16 декабря 2016

Как сказал Билл Филлипс, Scroller - это просто класс Android SDK, помогающий вычислять позиции прокрутки.У меня есть полный рабочий пример:

public class SimpleScrollableView extends TextView {
    private Scroller mScrollEventChecker;

    private int mLastFlingY;
    private float mLastY;
    private float mDeltaY;

    public SimpleScrollableView(Context context) {
        this(context, null, 0);
    }

    public SimpleScrollableView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SimpleScrollableView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mScrollEventChecker != null && !mScrollEventChecker.isFinished()) {
            return super.onTouchEvent(event);
        }

        final int action = event.getAction();

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mLastY = event.getY();
                return true;

            case MotionEvent.ACTION_MOVE:
                int movingDelta = (int) (event.getY() - mLastY);
                mDeltaY += movingDelta;
                offsetTopAndBottom(movingDelta);
                invalidate();
                return true;

            case MotionEvent.ACTION_UP:
                mScrollEventChecker = new Scroller(getContext());
                mScrollEventChecker.startScroll(0, 0, 0, (int) -mDeltaY, 1000);
                post(new Runnable() {
                    @Override
                    public void run() {
                        if (mScrollEventChecker.computeScrollOffset()) {
                            int curY = mScrollEventChecker.getCurrY();
                            int delta = curY - mLastFlingY;
                            offsetTopAndBottom(delta); // this is the method make this view move
                            invalidate();
                            mLastFlingY = curY;
                            post(this);
                        } else {
                            mLastFlingY = 0;
                            mDeltaY = 0;
                        }
                    }
                });
                return super.onTouchEvent(event);
        }

        return super.onTouchEvent(event);
    }
}

Приведенный выше демонстрационный пользовательский вид будет прокручиваться обратно в исходное положение после того, как пользователь освободит представление.Когда пользователь освобождает представление, вызывается метод startScroll (), и мы можем знать, какое значение расстояния должно быть для каждого отдельного сообщения.

Полный рабочий пример: Репозиторий Github

2 голосов
/ 02 июля 2014

Мы можем расширить класс Scroller, а затем перехватить соответствующие методы запуска анимации, чтобы отметить, что он был запущен, после того, как computeScrollOffset () вернет false, что означает значение завершения анимации, мы сообщаем прослушивателю вызывающей стороне:

public class ScrollerImpl extends Scroller {
    ...Constructor...

    private boolean mIsStarted;
    private OnFinishListener mOnFinishListener;

    @Override
    public boolean computeScrollOffset() {
        boolean result = super.computeScrollOffset();
        if (!result && mIsStarted) {
            try { // Don't let any exception impact the scroll animation.
                mOnFinishListener.onFinish();
            } catch (Exception e) {}
            mIsStarted = false;
        }
        return result;
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy) {
        super.startScroll(startX, startY, dx, dy);
        mIsStarted = true;
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        super.startScroll(startX, startY, dx, dy, duration);
        mIsStarted = true;
    }

    @Override
    public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) {
        super.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
        mIsStarted = true;
    }

    public void setOnFinishListener(OnFinishListener onFinishListener) {
        mOnFinishListener = onFinishListener;
    }

    public static interface OnFinishListener {
        void onFinish();
    }
}
2 голосов
/ 07 февраля 2012

Отличный ответ выше. Scroller # startScroll (...) действительно работает так же.

Например, источник для пользовательской прокрутки TextView по адресу: http://bear -polka.blogspot.com / 2009/01 / scrolltextview прокруткой-TextView-for.html

Устанавливает скроллер в TextView, используя TextView # setScroller (Scroller).

Источник для TextView SDK по адресу: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/widget/TextView.java#TextView.0mScroller

Показывает, что TextView # setScroller (Scroller) устанавливает поле класса, которое используется в ситуациях, таких как занесение в PointPointIntoView (int), где вызывается Scroller # scrollTo (int, int, int, int).

yieldPointIntoView () настраивает mScrollX и mScrollY (с некоторым кодом фрагментации SDK), затем вызывает invalidate (). Смысл всего этого в том, что mScrollX и mScrollY используются в таких методах, как onPreDraw (...), чтобы влиять на положение отображаемого содержимого представления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...