Android中实现滑动(中)----实现(2)

在了解了前面介绍的基础知识之后,下面就来看看具体的滑动实现,接下来会介绍7种方法,主要是结合《Android群英传》中学习的知识展开。这七种方法分别是:

(1)View绘制时的layout方法

(2)View绘制时根据系统封装好的offSetLeftAndRight以及offSetTopAndBottom接口实现View的布局定位

(3)通过View的布局参数layoutParams来重置View的margin值实现布局重新定位

(4)通过View的scrollTo和scrollBy方法

(5)通过Scroller类实现

(6)通过属性动画实现

(7)通过ViewDragHelper实现

对于滑动的实现,我会分为四个部分讲解,第一部分讲述(1)(2)(3)的实现方法,第二部分讲述(4)和(5)的实现,第三部分讲述属性动画方法实现,第四部分也是较复杂的部分讲述(7)的实现,下面我们就开始吧。本部分主要介绍scrollTo和scrollBy以及Scroller使用

1,scrollTo和scrollBy

任何一个View子类对象都可以调用这两个接口

1.1 两者的关系

scrollBy源码:

/**
 * 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实现的本质也是scrollTo

1.2 两者的作用和区别

(1)scrollTo(),view移动到指定坐标点

(2)scrollBy(),view依据当前的坐标点结合传入的偏移量进行移动

移动的效果:

如果是ViewGroup,那么屏幕展示的移动效果实际上是移动的其子view

如果是ImageView,Button这样的控件,那么屏幕展示的移动效果实际上是移动的其Content

比如下图示例:

我们移动的View,本质上移动的却是其Content,所以如果我们想实现移动一个View的效果,只需要移动其父布局即可。需要注意的是这里有一个相对的概念,也即子View向左移动,父布局就需要向右移动;上下也是同理。下面就来看看具体的示例:

2,代码示例

2.1  简单移动测试

ScrollActivity代码:

package com.hfut.operationscroll;

import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

/**
 * @author why
 * @date 2018-8-19 16:48:41
 */
public class ScrollActivity extends AppCompatActivity {

    int lastX = 0;
    int lastY = 0;
    private static final String TAG = "MainActivity";
    Button button;
    LinearLayout linearLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scroll);
        button = findViewById(R.id.test_button);
        linearLayout=findViewById(R.id.test_layout);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
        button.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int x = (int) event.getX();
                int y = (int) event.getY();
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        lastX = x;
                        lastY = y;
                        break;
                    case MotionEvent.ACTION_UP:
                        break;
                    case MotionEvent.ACTION_MOVE:
                        Log.d(TAG, "onTouch: "+ System.currentTimeMillis());
                        //方式一,通过视图坐标系计算偏移量
                        int offX = x - lastX;
                        int offY = y - lastY;
                        v.scrollBy(-offX,-offY);
                        linearLayout.scrollBy(-offX,-offY);
                        break;
                    default:
                        break;
                }
                return true;
            }
        });
    }

}

activity_scroll.xml代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/test_layout"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/test_button"
        android:layout_width="400dp"
        android:layout_height="400dp"
        android:text="拖我移动" />

</LinearLayout>

代码和第一部分差不多,偏移量的计算都一样,其中:

case MotionEvent.ACTION_MOVE:
    Log.d(TAG, "onTouch: "+ System.currentTimeMillis());
    int offX = x - lastX;
    int offY = y - lastY;
    v.scrollBy(-offX,-offY);
    linearLayout.scrollBy(-offX,-offY);
    break;

部分,里面两行关于移动的代码,如果把第一行注释掉,那么按钮和里面的text一起同步移动,如果两行全放开,那么按钮里面的text也会相对button边框移动,运行代码:

v.scrollBy(-offX,-offY);

注释后:

注释前:

2.2 使用scrollBy或者scrollTo模拟平滑滑动

      我们知道,使用这两个接口实现的滑动都是瞬间完成的,给客户的体验很不好,下面就结合这两个方法以及Timer和Handler实现一个平滑的滑动,因为都是基础知识,这里直接给出代码:

ScrollActivity代码:

package com.hfut.operationscroll;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.Switch;

import java.sql.Time;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author why
 * @date 2018-8-19 17:14:10
 */
public class ScrollActivity extends AppCompatActivity {

    public static final int DESTINATION=1;
    public static final int STARTPOINT=0;
    int quickCount = 1;
    int slowCount = 1;
    LinearLayout quickLinearLayout;
    LinearLayout slowLinearLayout;
    Switch slowOne;
    Switch quickOne;
    Scroller scroller;
    Button quickTrigger;
    Button slowTrigger;
    int movedDis = 0;
    int x = 0;
    int increment = 10;

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DESTINATION:
                    slowTrigger.setText("回来");
                    slowOne.setChecked(true);
                    break;
                case STARTPOINT:
                    slowTrigger.setText("慢移");
                    slowOne.setChecked(false);
                    break;
                default:
                    break;
            }
        }
    };

    private static final String TAG = "ScrollerActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scroller);
        quickLinearLayout = findViewById(R.id.quick_move_layout);
        slowLinearLayout = findViewById(R.id.slow_move_layout);
        slowOne = findViewById(R.id.slow_runner);
        quickOne = findViewById(R.id.quick_runner);
        quickTrigger = findViewById(R.id.quick_button);
        slowTrigger = findViewById(R.id.slow_button);
        x = (int) quickOne.getX();
    }


    public void quickMove(View view) {

        if (quickCount % 2 == 1) {
            //Log.d(TAG, "quickMove: " + total);
            //考虑到其本身的长度,所以这里减少了100sp
            quickLinearLayout.scrollBy(-(650 - x - 100), 0);
            quickOne.setChecked(true);
            quickTrigger.setText("回来");
        } else {
            quickLinearLayout.scrollBy(650 - x - 100, 0);
            quickOne.setChecked(false);
            quickTrigger.setText("瞬移");
        }
        quickCount++;
    }

    public void slowMove(View view) {
        if (slowCount % 2 == 1) {
            movedDis = 0;
            final Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    if (540 - x >= movedDis) {
                        movedDis += increment;
                        slowLinearLayout.scrollBy(-increment, 0);
                    } else {
                        Message message=new Message();
                        message.what=DESTINATION;
                        handler.sendMessage(message);
                        timer.cancel();
                    }
                }
            }, 200, 50);
        } else {
            movedDis = 0;
            final Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    if (540 - x >= movedDis) {
                        movedDis += increment;
                        slowLinearLayout.scrollBy(increment, 0);
                    } else {
                        Message message=new Message();
                        message.what=STARTPOINT;
                        handler.sendMessage(message);
                        timer.cancel();
                    }
                }
            }, 200, 50);
        }
        slowCount++;
    }
}

activity_scroll.xml代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.hfut.operationscroll.ScrollActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:text="瞬移"
            android:id="@+id/quick_button"
            android:onClick="quickMove"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <LinearLayout
            android:id="@+id/quick_move_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <Switch
                android:id="@+id/quick_runner"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="15sp" />
        </LinearLayout>

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:text="慢移"
            android:id="@+id/slow_button"
            android:onClick="slowMove"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <LinearLayout
            android:id="@+id/slow_move_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Switch
                android:id="@+id/slow_runner"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="15sp" />
        </LinearLayout>

    </LinearLayout>

</LinearLayout>

运行结果:

      这部分主要还是理解使用这种移动的原理,这对于后面的难点滑动冲突问题的解决至关重要。

猜你喜欢

转载自blog.csdn.net/hfut_why/article/details/81841285
今日推荐