scrollTo:绝对位置滑动
scrollBy:相对位置滑动
//生硬的滑动
((View) getParent()).scrollTo(-100, -100);
((View) getParent()).scrollBy(-100, -100);
linear.scrollBy((int) getResources().getDimension(R.dimen.px_500), (int) getResources().getDimension(R.dimen.px_500));
<resources>
<dimen name="px_500">-500pxdimen>
resources>
注意:
1:站在子view的角度(也就是你想移动子view),直接用scrollTo,scrollBy是不行的,应该调用父控件的scrollTo,scrollBy;站在父view的角度(也就是你想移动父view中的子view),直接用scrollTo,scrollBy是可以的。总之,scrollTo,scrollBy移动的是View内的内容;
2:向右移动和向下移动,都为负值;
3:x、y、left、top、right、bottom的值是不会变的。
4:它只是内容区域的移动,本身view是不移动的,但是内容区域变了(如果超出自己的区域 就显示不出来)
package com.example.viewmovedaemon.view;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.Scroller;
/**
* Created by yuanpk on 2017/11/29.
*/
public class CustomLinearLayout extends LinearLayout {
private Scroller scroller;
public CustomLinearLayout(Context context) {
super(context);
}
public CustomLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
scroller = new Scroller(context);
}
//缓慢滚动到指定位置,调用该方法即可
public void smoothScrollTo(int destX, int destY, int duration) {
int scrollX = getScrollX();
int deltaX = destX - scrollX;
int scrollY = getScrollY();
int deltaY = destY - scrollY;
scroller.startScroll(scrollX, 0, deltaX, deltaY, duration * 1000);
invalidate();
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}
}
拿到该自定义控件后,直接调用该方法,该自定义控件中的子view就实现弹性滑动啦:
linear.smoothScrollTo(-500, -500, 9);
这样:
//渐进匀速的滑动
/* AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
ObjectAnimator.ofFloat(button, "translationX", 0, 100).setDuration(6 * 1000),
ObjectAnimator.ofFloat(button, "translationY", 0, 100).setDuration(6 * 1000)
);
animatorSet.start();*/
//生硬的滑动
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
ObjectAnimator.ofFloat(this, "translationX", 100),
ObjectAnimator.ofFloat(this, "translationY", 100)
);
animatorSet.start();
或者这样:
//渐进匀速的滑动
ObjectAnimator.ofFloat(button, "translationX", 0, 500).setDuration(6 * 1000).start();
ObjectAnimator.ofFloat(button, "translationY", 0, 500).setDuration(6 * 1000).start();
或者这样:
//生硬的滑动
button.setTranslationX(300);
button.setTranslationY(300);
注意:
移动之后,x、y的值改变了,但是left、top、right、bottom值没有改变。
这边也许有疑问,x和left为什么不一样?
查看getX()方法的源码:
getX() {
return mLeft + getTranslationX();
}
//渐进匀速的滑动
TranslateAnimation anim = new TranslateAnimation(0, 500, 0, 500);
anim.setFillAfter(true);
anim.setDuration(2 * 1000);
button.startAnimation(anim);
注意:
位移动画过后,x、y、left、top、right、bottom都没有变。
这就是为什么位移动画过后,View的点击事件没有效果的原因,因为View的属性没有变。这也是属性动画应运而生的原因之一。
//生硬的滑动
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) getLayoutParams();
lp.leftMargin = getLeft() + 100;
lp.topMargin = getTop() + 100;
setLayoutParams(lp);
注意:
1:此方法同样也是完完全全移动View的位置。
2:和layout中第2条注意一样。
//生硬的滑动
button.layout(button.getLeft() + 300, button.getTop() + 100, button.getRight() + 300, button.getBottom() + 100);
//和下面的方法一个道理
/*button.setLeft(button.getLeft() + 300);
button.setRight(button.getRight() + 300);
button.setTop(button.getTop() + 100);
button.setBottom(button.getBottom() + 100);*/
注意:
1:此方法是完完全全移动View的位置,View的x、y、left、top、right、bottom都会相应的增加对应的px;
2:该方法若在Activity中,使用的话,应在 public void onWindowFocusChanged(boolean hasFocus)方法中或者延时几秒钟在使用该方法,否则不生效。具体原因参考,参考 android进阶篇之View——基础篇
//生硬的滑动
offsetLeftAndRight(100);
offsetTopAndBottom(100);
注意:
1:此方法和layout一样,都是完完全全移动View的位置。
2:和layout中第2条注意一样。
相关博客:
View的三种移动方式
android view的多种移动方式(测试集合)
移动View的位置的几种方法
Android View移动的六种方法小结
在此多说一些题外话:
RequestLayout():
Invalidate():
layout():
总结:比如说它的LayoutParams发生了改变,需要父布局对其进行重新测量、布局、绘制这三个流程,往往使用requestLayout。而invalidate则是刷新当前View,使当前View进行重绘,不会进行测量、布局流程,因此如果View只需要重绘而不需要测量,布局的时候,使用invalidate方法往往比requestLayout方法更高效。
参考文章:
Android View 深度分析requestLayout、invalidate与postInvalidate
很不错
ByeBurger
也很不错
LBehavior
顶部标题栏随滑动时的渐变隐藏和渐变显示
Android手把手教你实现滑动隐藏(GeastureDetector使用)