我是 Android 开发的新手,我只是想了解一些有关 Scroller 小部件 (android.widget.Scroller) 的信息。它如何为视图设置动画?如果 Animation 对象存在,是否可以访问?如果是这样,怎么做?我已经阅读了源代码,但找不到任何线索,或者我太新了?
我只是想在 Scroller 完成滚动后做一些操作,比如
m_scroller.getAnimation().setAnimationListener(...);
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 的细节应该类似。
正如 Bill Phillips 所说,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 存储库
上面的答案很好。Scroller#startScroll(...) 确实以相同的方式工作。
例如,自定义滚动 TextView 的来源:http: //bear-polka.blogspot.com/2009/01/scrolltextview-scrolling-textview-for.html
使用 TextView#setScroller(Scroller) 在 TextView 上设置 Scroller。
SDK 的 TextView 的来源: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) 设置了一个类字段,该字段用于在诸如调用 Scroller#scrollTo(int, int, int, int) 的情况下使用。
bringPointIntoView() 调整 mScrollX 和 mScrollY(带有一些 SDK 分片代码),然后调用 invalidate()。所有这一切的重点是 mScrollX 和 mScrollY 用于 onPreDraw(...) 等方法中,以影响视图绘制内容的位置。
我们可以扩展Scroller
该类,然后拦截相应的动画开始方法以标记已开始,在computeScrollOffset()返回 false 表示动画完成的值之后,我们通过 Listener 通知调用者:
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();
}
}