1).实现滑动的方式:
- 通过动画给View增加平移滑动的效果
- 通过改变View的LayoutParams使得View重新布局
- 通过View自身提供的ScrollTo/scrollBy方法实现滑动
- 通过layout
1.通过动画
这里以属性动画为例:
ObjectAnimator.ofFloat(targetView,"translationX",0,100).setDuration(1000).start();
2.通过改变View的LayoutParams
示例:
RelativeLayout.LayoutParams layoutParams (RelativeLayout.LayoutParams) targetView.getLayoutParams();
layoutParams.leftMargin +=100;
targetView.setLayoutParams(layoutParams);
3.通过ScrollTo/scrollBy
/**
mScrollX和mScrollY表示:View的内容(content)相对于View本身在水平或垂直方向的偏移量.
**/
public final int getScrollX() {
return mScrollX;
}
public final int getScrollY() {
return mScrollY;
}
/**
* Set the scrolled position of your view. This will
* cause a call to {@link #onScrollChanged(int, int,
* int,int)}and the view will be invalidated.
* @param x the x position to scroll to
* @param y the y position to scroll to
*/
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
}
- 用法
targetView.scrollTo(100,0),targetView的内容向左滑动到(-100,0)。
targetView.scrollTo(-100,0),targetView的内容向右滑动到(100,0)。
targetView.scrollBy(100,0),targetView的内容相对于上个位置向左滑动100像素。
targetView.scrollBy(-100,0),targetView的内容相对于上个位置向右滑动100像素。
- 滑动的是ViewGroup/View的内容,不是ViewGroup/View本身。
- 滑动是一瞬间的。
- scrollBy()底层是由scrollTo()实现的
- scrollTo()时为何参数值和坐标反向?
由scrollTo(int x, int y)的注释可知调用该方法会回调onScrollChanged()方法,并且会重新绘制view,draw()过程中最终会调用invalidate()方法。
public void invalidate(int l, int t, int r, int b) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
//scrollTo时为何参数和坐标反向的真实原因
invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false);
特别注意:如果你给一个ViewGroup调用scrollTo()方法滚动的是ViewGroup里面的内容,如果想滚动一个ViewGroup则再给他嵌套一个外层,滚动外层即可。
2).弹性滑动实现方式:
1. Scroller
使用示例:
Scroller mScroller= new Scroller(mContext);
/**
* 缓慢滚动到指定位置
* @param destX 指定滚动到的X轴位置
* @param destY 指定滚动到的Y轴位置
*/
private void smoothScrollTo(int destX, int destY) {
//获取当前滚动的距离
int scrollX = getScrollX();
//获取需要滚动的偏移量
int delta = destX - scrollX;
//设置1000ms内滚动到delta位置,而效果就是慢慢滑动
mScroller.startScroll(scrollX, 0, delta, 0, 1000);
invalidate();
}
/**
* 持续滚动,实现慢慢滑动
*/
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
}
2.
ObjectAnimator.ofFloat(targetView,"translationX",0,100).setDuration(100).start();
3.值动画+layoutParams或值动画+scrollTo/scrollBy
ValueAnimator animator = ValueAnimator.ofFloat(0, 100 );
animator.setTarget(targetView);
animator.setDuration(1000).start();
animator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
float value=(Float) animation.getAnimatedValue();
targetView.ScrollTo(value,0);
}
4.handler +scrollTo/scrollBy
private static final int MESSAGE_SCROLL_TO = 1;
private static final int FRAME_COUNT = 30;
private static final int DELATED_TIME = 33;
private int mCount = 0;
@suppressLint("HandlerLeak")
private Handler handler = new handler(){
public void handleMessage(Message msg){
switch(msg.what){
case MESSAGE_SCROLL_TO:
mCount ++ ;
if (mCount <= FRAME_COUNT){
float fraction = mCount / (float) FRAME_COUNT;
int scrollX = (int) (fraction * 100);
mButton1.scrollTo(scrollX,0);
mHandelr.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO , DELAYED_TIME);
}
break;
default : break;
}
}
}