scrollBy与scrollTo
在view中都有scrollBy和scrollTo的两个方法,所以所有的view控件都是可以实现滚动的,
/**
* 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();
}
}
}
/**
* Move 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 amount of pixels to scroll by horizontally
* @param y the amount of pixels to scroll by vertically
*/
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
scrollBy是让当前的这个View在当前的位置上向某个方向移动(基于当前位置向某个方向移动多少),而scrollTo是移动到一个确切的目的地
这里涉及两个变量mScrollX和mScrollY,mScrollX的意思就是view的内容的左边缘与view的左边缘的水平距离,单位为px,而mScrollY就是view内容的上边缘与View的上边缘的距离
可以通过getScrollX 和getScrollY得到,默认是0
这里说的View的滑动,指的是view内容的滑动,view的位置是不会改变的
看例子:
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity {
private Button mScrollTo;
private Button mScrollBy;
private LinearLayout root;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mScrollTo = (Button) this.findViewById(R.id.scrollToBut);
mScrollBy = (Button) this.findViewById(R.id.scrollByBut);
root = (LinearLayout) this.findViewById(R.id.root);
mScrollBy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
root.scrollBy(-60, -100);
}
});
mScrollTo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
root.scrollTo(-60, -100);
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/root"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.jinxiong.scroller1.MainActivity">
<Button
android:id="@+id/scrollToBut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="scrollToBut"
/>
<Button
android:id="@+id/scrollByBut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="scrollByBut"/>
</LinearLayout>
这里涉及到一个就是它滑动的方向问题,跟view的位置坐标相反
(view的位置坐标)
而它滑动的方向刚刚相反,上图中的+变为-
使用动画
使用动画滑动view 实际上改变的是view 的translationX 和translationY的值,可以使用view动画(补间动画),还可以使用属性动画
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView textView = (TextView) this.findViewById(R.id.textView);
textView.startAnimation(AnimationUtils.loadAnimation(this, R.anim.test));
// TranslateAnimation animation = new TranslateAnimation(0, 0, 0, 100);
// animation.setDuration(5000);
// textView.startAnimation(animation);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "click" + textView.getTranslationY(), Toast.LENGTH_SHORT).show();
}
});
// ObjectAnimator.ofFloat(textView, "translationY", 0, 100).start();
}
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000"
>
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="0"
android:toYDelta="100"/>
</set>
如果想要动画停止之后留在动画的最后一个位置的话
android:fillAfter="true"
把这个设为true,其实补间(view)动画并没有真正的改变这个view的布局,也就是说这个view的真正位置还是在动画开始那个地方,view动画操作的是这个view的影像
上面为列子,当你加上fillAfter = true 之后,动画结束之后你点击你所看到的textView的位置,是不会有Toast出现的,当你点击textView的最开始的地方,就会有Toast出现
Toast显示这个view的translationX和Y是为0,所以并没有改变view的真正布局
当然你可以是有属性动画,
ObjectAnimator.ofFloat(textView, "translationY", 0, 100).start();
这个就可以解决这个问题,因为这个属性动画是通过改变view的translationX和Y的值的
改变布局的参数
就是改变LayoutParams的值,比如书我想把view向左移动100px 那么就可以使marginLeft + 100
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView textView = (TextView) this.findViewById(R.id.textView);
final ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) textView.getLayoutParams();
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "click" + textView.getTranslationY(), Toast.LENGTH_SHORT).show();
marginLayoutParams.leftMargin += 100;
textView.requestLayout();
}
});
}
比较
scrollTo/scrollBy:
方便的实现滑动的效果,不会影响view内部元素的点击事件,缺点:它只是滑动view的内容,而并非滑动view本身
动画
view动画的缺点是不是真正的去改变view的布局,属性动画就没有这个缺点,实际使用中,动画适用在那些不需要交互的view上面比较好,并且比较炫酷的效果都是动画实现的
改变布局参数
使用稍微麻烦,没什么了,常用在那些需要交互的view上面
下面有个例子,可以拖动整个view,在屏幕上随意滑动
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout relativeLayout = (RelativeLayout) this.findViewById(R.id.root);
relativeLayout.setOnTouchListener(new View.OnTouchListener() {
int mLastX;
int mLastY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
mLastX = (int) event.getRawX();
mLastY = (int) event.getRawY();
break;
}
case MotionEvent.ACTION_UP: {
int x = (int) event.getRawX();
int y = (int) event.getRawY();
v.setTranslationX(v.getTranslationX() + x - mLastX);
v.setTranslationY(v.getTranslationY() + y - mLastY);
break;
}
}
return true;
}
});
通过平移这个view 达到这个效果