Android群英传——Scroll

来源:互联网 发布:qq数据导入工具在哪 编辑:程序博客网 时间:2024/06/05 02:38

这篇博客的是对Android群英传,和网上的一些学习资料以及官方文档中关于Scroller的总结。主要针对scrollBy和scorllTo的区别以及Scroller类进行总结。

Scroll

使用scrollTo和scrollBy向下移动时,需要传入负数值:

scrollTo(-30,-30);scrollBy(-30,-30);

这篇文章从源码角度告诉我们为什么传入负数,向下移动

从源码角度,坐标系是不变的,由于源码中的这段代码tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY)设置一个view需要绘制的脏矩形,mScrollX和mScrollY都是作为参数的减数(负负得正,负正得负),当scrollTo()的传入参数为负的时候,view就向坐标轴正方向滚动;当为正的时候,view就向坐标轴负方向滚动。
这里写图片描述

我们也可以简单理解为坐标系的方向这样的:
这里写图片描述

scrollBy和ScrollTo的区别

scrollBy是相对于目前的位置移动指定距离
scrollTo是移动到指定的位置

效果如图,点击scrollTo后会跳到指定的位置,继续点击是没有效果的。然而点击scrollBy会相对于当前位置,每次点击都移动一段指定距离。当scrollBy移动一段距离后,再点击scrollTo,它会跳会原来指定的位置。

这里写图片描述

这里使用的是 Linearlayout来调用scrollTo和scrollBy。如果直接使用view调用时,移动的只是view里面的内容,也就是Button中的text。我们也可以使用((View)getParent)来获得父类。

public class MainActivity extends AppCompatActivity {    Button btn_scrollBy;    Button btn_scrollTo;    LinearLayout layout;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        btn_scrollBy = (Button) findViewById(R.id.btn_scrollBy);        btn_scrollTo = (Button) findViewById(R.id.btn_scrollTo);        layout = (LinearLayout) findViewById(R.id.linearlayout);        btn_scrollBy.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                View viewGroup = (View) v.getParent();               layout.scrollBy(-30,-30);            }        });        btn_scrollTo.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                layout.scrollTo(-30,-30);            }        });    }}

我们发现使用scrollTo,和scrollBy移动时,都是瞬间移动,视觉感受不是很好,这时我们就可以调用Scroller类来实现平滑移动的效果。

Scroller

使用Scroller实现时需要遵循以下几个步骤:

  1. 创建Scroller的实例

  2. 重写computeScroll()方法,并在其内部完成平滑滚动的逻辑

  3. 调用startScroll()方法来初始化滚动数据并刷新界面


创建scroller实例

 Scroller  mScroller = new Scroller(context);

computeScroll是Scroller的核心算法,系统在绘制View的时候会在draw()方法中调用该方法。这个方法实际上是调用scrollTo方法。通过不断的瞬间移动一个很小的距离,来实现整体上的平滑移动的效果。

其中我们使用scroller.computeScrollOffsert()方法来进行判断,这个方法是判断移动是否结束,如果未结束会返回true,结束返回false。

mScroller.getCurrX();//在scroll中当前x的偏移量mScroller.getCurrY();//在scroll中当前y的偏移量

@Override    public void computeScroll() {        super.computeScroll();        //判断Scroller是否执行完毕        if (mScroller.computeScrollOffset()) {        //根据当前x,y的偏移量移动            ((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            // invalidate()->draw()->computeScroll()            invalidate();        }    }

简单介绍下startScroll()方法,一个是有duration,另一个是无duration

void startScroll (int startX, //开始时x的位置                int startY, //开始时y的位置                int dx, //x的偏移量                int dy, //y的偏移量                int duration)//滚动的持续时间void startScroll (int startX,                 int startY,                 int dx,                 int dy)

效果图,这个是没有设置duration的效果图

这里写图片描述


设置duration为2000ms的效果图,可以看到滑动更加的平滑

这里写图片描述

这个简单的例子,是将startScroll设置在MotionEvent.ACTION_UP时,让view回到原来的位置上。

关键代码:
使用startScroll时要调用invalidate()方法进行刷新

 //当手指离开时            case MotionEvent.ACTION_UP:                View viewGroup = (View) getParent();                mScroller.startScroll(viewGroup.getScrollX(),                        viewGroup.getScrollY(),                        -viewGroup.getScrollX(),//偏移量,回到初始位置                        -viewGroup.getScrollY());                invalidate();//刷新                break;

完整代码:

public class DragView extends View {    private int lastX;    private int lastY;    private Scroller mScroller;  public DragView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        mScroller = new Scroller(context);    } @Override    public void computeScroll() {        super.computeScroll();        //判断Scroller是否执行完毕        if (mScroller.computeScrollOffset()) {            ((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            // invalidate()->draw()->computeScroll()            invalidate();        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int x = (int) event.getX();        int y = (int) event.getY();        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                lastX = (int) event.getX();//记录下按下时的坐标                lastY = (int) event.getY();                break;            case MotionEvent.ACTION_MOVE:                int offsetX = x - lastX;//计算当前坐标和按下时坐标的差值,即偏移量                int offsetY = y - lastY;                //实现跟着手指移动                ((View) getParent()).scrollBy(-offsetX, -offsetY);                break;            //当手指离开时            case MotionEvent.ACTION_UP:                View viewGroup = (View) getParent();                mScroller.startScroll(viewGroup.getScrollX(),                        viewGroup.getScrollY(),                        -viewGroup.getScrollX(),//偏移量,回到初始位置                        -viewGroup.getScrollY());                invalidate();//刷新                break;        }        return true;    }}

布局代码:

<LinearLayout 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:id="@+id/linearlayout"    tools:context=".MainActivity">    <example.com.myapplication2.DragView        android:background="@color/colorAccent"        android:layout_width="100dp"        android:layout_height="100dp" /></LinearLayout>

MainActivity:

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }}
原创粉丝点击