View滑动的常见方式
今天头条的面试官问起了实现View滑动的方式,其实前几天刚刚看过,但还是没能答上来,这里再来总结一遍。
1、使用scrollTo/scrollBy
为了实现View滑动,Android专门提供了这两个方法让我们使用。这两个函数的区别是scrollBy提供的是基于当前位置的相对滑动,而scrollTo提供的是基于起始位置的绝对滑动。
需要注意的是实际的滑动方向与我们想当然的方向不同,这个问题与View的内部变量mScrollX和mScrollY的含义有关,scrollTo函数与scrollBy函数实际上就是对这两个变量做出修改。
mScrollX:View的左边缘坐标减去View内容的左边缘坐标。
mScrollY:View的上边缘坐标减去View内容的上边缘坐标。
另外一个需要注意的地方是超出View边缘范围的内容是不会显示的。
2、使用动画
动画的方式主要是操作View的translationX与translationY属性。可以使用XML文件自定义动画效果也可以使用属性动画实现。
2.1、自定义动画
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true"> <translate android:duration="100" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="100" android:toYDelta="0" android:interpolator="@android:anim/linear_interpolator"/> </set>
View view = findViewById(R.id.target_view); Animation animation = AnimationUtils.loadAnimation(context, R.anim.target_animation); view.startAnimation(animation);
注意在XML文件中有一个fillAfter属性,如果设置为false的话当动画结束时View会恢复到原来的位置。
2.2、属性动画
View view = findViewById(R.id.target_view); ObjectAnimator.ofFloat(view, "translationX", 0, 100) .setDuration(100) .start();
3、改变布局参数
第三种方法是改变View的LayoutParams,与之前的方法相比,这种方法显得不是很正统,但是也可以实现我们的需求。举个例子,假如我们想把一个View右移100dp,那么最简单的方式就是把它LayoutParams里的marginLeft参数的值增加100dp。但这种方法要根据View所在的父布局灵活调整,在一些情况下改变margin值并不能改变View的位置。
View view = findViewById(R.id.target_view); ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view .getLayoutParams(); params.leftMargin += 10; mTargetTextView.setLayoutParams(params);
还有一个相似的方法,但可用性要好一些,那就是调用View的layout方法,直接修改View相对于父布局的位置。
int offsetX = 10; View view = findViewById(R.id.target_view); view.layout(mTargetTextView.getLeft() + offsetX, view.getTop(), view.getRight() + offsetX, view.getBottom());
4、使用Scroller实现渐进式滑动
上边提到的滑动方式有一个共同的缺点那是他们都不是渐进式的滑动。实现渐进式滑动的共同思想就是将一个滑动行为分解为若干个,在一段时间内按顺序完成。
这里介绍使用Scroller类的实现方式。
public class ScrollerTextView extends TextView { private Scroller mScroller; public ScrollerTextView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); mScroller = new Scroller(context); } public void smoothScrollBy(int dx, int dy) { int scrollX = getScrollX(); int scrollY = getScrollY(); mScroller.startScroll(scrollX, scrollY, dx, dy); invalidate(); } @Override public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } } }