Android实现View滑动的几种方式

什么是View?实现View滑动的方式有哪些?
1. 关于View我们需要知道的

(1)什么是View?

Android中的View类是所有UI控件的基类(Base class),也就是说我们平时所有到的各种UI控件,比如Button、ImagView等等都继承自View类。LinearLayout、FrameLayout等布局管理器的直接父类是ViewGroup,而ViewGroup也有View类派生。总的来说,View是对UI控件的抽象,它代表了屏幕上的一个矩形区域。通过继承View,并重写相应方法,我们就能够实现具有各种外观及行为的UI控件。Button等控件我们之所以能够直接拿来即用,是因为Google已经帮我们完成了继承View并重写方法的工作。

(2)View的位置

View在屏幕上的位置由它的以下四个参数所决定:

top:View的左上角的纵坐标,对应着View类中的成员变量mTop,可由getTop方法获得;
left:View的左上角的横坐标,对应着View类中的成员变量mLeft,可由getLeft方法获得;
bottom:View的右下角的纵坐标,对应着View类中的成员变量mBottom,可由getBottom方法获得;
right:View的右下角的横坐标,对应着View类中的成员变量mRight,可由getRight方法获得。
    注意,以上的坐标都是相对于父View来说的,也就是说,坐标都是相对坐标,因为子View的布局是由父View来完成的。如下图所示:

Android实现View滑动的几种方式

有了这四个参数,计算View的宽高就很容易了:width = right - left;height = bottom - top。关于View还有两个参数需要我们注意:translationX代表View平移的水平距离,translationY代表View平移的竖直距离;x、y分别为View的左上角的横纵坐标。View若经过了平移,改变的是它的x、y(代表当前View的左上角位置),它的四个位置参数代表了View的原始位置信息,是始终不变的。View在平移的过程中始终满足如下关系:

x = left + translationX; y = top + translationY。

2. 实现View滑动的几种方式
    我们在使用View的过程中,经常需要实现View的滑动效果。比如ListView、跟随手指而移动的自定义View等等,前者的滑动效果是SDK为我们提供的,而对于我们自定义View的滑动效果就需要我们自己来实现。下面我们来详细介绍以下实现View滑动的几种方式。

(1)使用scrollTo/scrollBy实现View的滑动

实现滑动的最朴素直接的方式就是使用View类自带的scrollTo/scrollBy方法了。scrollBy方法是滑动指定的位移量,而scrollTo方法是滑动到指定位置。这两个方法的源码如下:

/**
 * 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;
   onScrollChanged(mScrollX, mScrollY, oldX, oldY);
   if (!awakenScrollBars()) {
    invalidate();
   }
  }
} 

/**
 * 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);
}

通过以上代码的33~35行我们可以看到,scrollBy方法内部也是调用了scrollTo方法来实现。以上源码中我们注意到了mScrollX和mScrollY成员变量,前者是View的左边缘减去View的内容的左边缘,后者是View的上边缘减去View的内容的上边缘。示意图如下:

Android实现View滑动的几种方式

上图中,黑色边框代表View在屏幕上对应的矩形区域,蓝色边框代表View的内容。在上图中,我们调用scrollTo/scrollBy把View向右滚动了一定距离。实际上,调用scrollBy/scrollTo方法只能实现View的内容的滚动,而View的四个位置参数是保持不变的。想一下我们平常使用ListView时,滚动的就是ListView的内容,而ListView本身在屏幕上的位置是不变的。上图中,黑色左边(即View的左边缘)减去蓝色左边(即View的内容的左边缘)即可得到mScrollX。由此我们还可以知道,向右滚动时mScrollX负的,向左滚动时mScrollX是正的。同理我们可以知道,向下滚动时,mScrollY是负的,向上滚动时,mScrollY是正的。

经过以上的分析,我们了解到使用scrollTo/scrollBy方法实现View的滑动是很简单直接的,那么简单的背后有什么代价呢?代价就是滑动不是“弹性的”,弹性滑动指的是View的滑动应该是一个先加速再逐渐减速到停止的过程,这样看起来很平滑,不会很突兀。scrollTo/scrollBy方法实现的滑动看起来就会很突兀,这样的用户体验很不好。在解决这个问题之前,我们先来看看实现View滑动的其他方法。

 (2)使用动画来实现View的滑动

使用动画来实现View的滑动主要通过改变View的translationX和translationY参数来实现,使用动画的好处在于滑动效果是平滑的。上面我们提到过,View的x、y参数决定View的当前位置,通过改变translationX和translationY,我们就可以改变View的当前位置。我们可以使用属性动画或者补间动画来实现View的平移。

首先,我们先来看一下如何使用补间动画来实现View的平移。补间动画资源定义如下(anim.xml):

<?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:interpolator="@android:anim/linear_interpolator"
  android:toXDelta="100"
  android:toYDelta="100"/>

</set>

然后在onCreat方法中调用startAnimation方法即可。使用补间动画实现View的滑动有一个缺陷,那就是移动的知识View的“影像”,这意味着其实View并未真正的移动,只是我们看起来它移动了而已。拿Button来举例,假若我们通过补间动画移动了一个Button,我们会发现,在Button的原来位置点击屏幕会出发点击事件,而在移动后的Button上点击不会触发点击事件。

接下来,我们看看如何用属性动画来实现View的平移。使用属性动画实现View的平移更加简单,只需要以下一条语句:

ObjectAnimator.ofFloat(targetView, "translationX", 0, 100).setDuration(100).start();

以上代码即实现了使用属性动画把targetView在100ms内向右平移100px。使用属性动画的限制在于真正的属性动画只可以在Android 3.0+使用(一些第三方库实现的兼容低版本的属性动画不是真正的属性动画),优点就是它可以真正的移动View而不是仅仅移动View的影像。

经过以上的描述,使用属性动画实现View的滑动看起来是个不错的选择,而且一些View的复杂的滑动效果只有通过动画才能比较方便的实现。

(3)通过改变布局参数来实现View的滑动

通过改变布局参数来实现View的滑动的思想很简单:比如向右移动一个View,只需要把它的marginLeft参数增大,向其它方向移动同理,只需改变相应的margin参数。还有一种比较拐弯抹角的方法是在要移动的View的旁边预先放一个View(初始宽高设为0)。然后比如我们要向右移动View,只需把预先放置的那个View的宽度增大,这样就把View“挤”到右边了。代码示例如下:

MarginLayoutParams params = (MarginLayoutParams) mButton.getLayoutParams();
params.leftMargin += 100;
mButton.requestLayout();

以上代码即实现了把mButton向右滑动100px。通过改变布局参数来实现的滑动效果也不是平滑的。

(4)使用Scroller来实现弹性滑动

上面我们提到了使用scrollTo/scrollBy方法实现View的滑动效果不是平滑的,好消息是我们可以使用Scroller方法来辅助实现View的弹性滑动。使用Scroller实现弹性滑动的惯用代码如下:

Scroller scroller = new Scroller(mContext);

private void smoothScrollTo(int dstX, int dstY) {
 int scrollX = getScrollX();
 int delta = dstX - scrollX;
 scroller.startScroll(scrollX, 0, delta, 0, 1000);
 invalidate();
}

@Override
public void computeScroll() {
 if (scroller.computeScrollOffset()) {
  scrollTo(scroller.getCurrX(), scroller.getCurY());
  postInvalidate();
 }
}

我们来看一下以上的代码。第4行中,我们获取到View的mScrollX参数并存到scrollX变量中。然后在第5行计算要滑动的位移量。第6行调用了startScroll方法,我们来看看startScroll方法的源码:

public void startScroll(int startX, int startY, int dx, int dy, int duration) {
 mMode = SCROLL_MODE;
 mFinished = false;
 mDuration = duration;
 mStartTime = AnimationUtils.currentAnimationTimeMillis();
 mStartX = startX;
 mStartY = startY;
 mFinalX = startX + dx;
 mFinalY = startY + dy;
 mDeltaX = dx;
 mDeltaY = dy;
 mDurationReciprocal = 1.0f / (float) mDuration; 

 mViscousFluidScale = 8.0f; 

 mViscousFluidNormalize = 1.0f;
 mViscousFluidNormalize = 1.0f / viscousFluid(1.0f);
}

从以上的源码我们可以看到,startScroll方法中并没有进行实际的滚动操作,而是把startX、startY、deltaX、deltaY等参数都保存了下来。那么究竟怎么实现View的滑动的呢?我们先回到Scroller惯用代码。我们看到第7行调用了invalidate方法,这个方法会请求重绘View,这会导致View的draw的方法被调用,draw的方法内部会调用computeScroll方法。我们来看看第13行,调用了scrollTo方法,并传入mScroller.getCurrX()和mScroller.getCurrY()方法作为参数。那么获取到的这两个参数是什么呢?这两个参数是在第12行调用的computeScrollOffset方法中设置的,我们来看看这个方法中设置这两个参数的相关代码:

public boolean computeScrollOffset() {
 ...
 int timePassed = (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime);
 if (timePassed < mDuration) {
  switch (mMode) {
   case SCROLL_MODE:
    final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
    mCurrX = mStartX + Math.round(x * mDeltaX);
    mCurrY = mStartY + Math.rounc(y * mDeltaY);
    break;
  ...
  }
 }
 return true;
}

以上代码中第8行和第9行设置的mCurrX和mCurrY即为以上scrollTo的两个参数,表示本次滑动的目标位置。computeScrollOffset方法返回true表示滑动过程还未结束,否则表示结束。

通过以上的分析,我们大概了解了Scroller实现弹性滑动的原理:invaldate方法会导致View的draw方法被调用,而draw会调用computeScroll方法,因此重写了computeScroll方法,而computeScrollOffset方法会根据时间的流逝动态的计算出很小的一段时间应该滑动多少距离。也就是把一次滑动拆分成无数次小距离滑动从而实现“弹性滑动”。

本文提到的所有三种滑动方式的完整demo

以上就是本文的全部内容,希望对大家学习Android软件编程有所帮助。

时间: 2016-04-20

Android利用ViewPager实现滑动广告板实例源码

•android-support-v4.jar,这是谷歌官方给我们提供的一个兼容低版本Android设备的软件包,里面包囊了只有在Android3.0以上可以使用的api.而ViewPager就是其中之一,利用它我们可以做很多事情,从最简单的导航,到页面切换菜单等等. •ViewPager的功能就是可以使视图滑动,就像Lanucher左右滑动那样. •本Demo向大家演示ViewPager的使用,并在用户未滑动View时,每隔5s钟自动切换到下一个View(循环切换),而当用户有Touch到Vi

Android 利用ViewPager实现图片可以左右循环滑动效果附代码下载

首先给大家展示靓照,对效果图感兴趣的朋友可以继续往下阅读哦. ViewPager这个小demo实现的是可以左右循环滑动图片,下面带索引,滑到最后一页在往右滑动就要第一页,第一页往左滑动就到最后一页,上面是效果图,用美女图片是我一贯的作风,呵呵  1.    首先看一些layout下的xml <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width=&qu

Android手势滑动实现ImageView缩放图片大小

本文推出了两种Android手势实现ImageView缩放图片大小的方法,分享给大家供大家参考,具体内容如下 方法一: 将以下代码写到MulitPointTouchListener.java中,然后对你相应的图片进行OnTouchListener. 例如:imageView.setOnTouchListener(new MulitPointTouchListener ()); 在xml中要将ImageView的缩放格式改成Matrix 例如:android:scaleType="matrix&q

Android中实现监听ScrollView滑动事件

时候我们需要监听ScroView的滑动情况,比如滑动了多少距离,是否滑到布局的顶部或者底部.可惜的是SDK并没有相应的方法,不过倒是提供了一个 复制代码 代码如下: protected void onScrollChanged(int x, int y, int oldx, int oldy) 方法,显然这个方法是不能被外界调用的,因此就需要把它暴露出去,方便使用.解决方式就是写一个接口, 复制代码 代码如下: package com.example.demo1;    public inter

android 通过向viewpage中添加listview来完成滑动效果(类似于qq滑动界面)

文件名:page.xml 复制代码 代码如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="fill_parent"    android:layout_height="fill

Android ViewPager无限循环实现底部小圆点动态滑动

页面拖动到最后一页 再向下滑动回复到 第一页,第一页向前滑动回到 最后一页 同时,底部红色小圆点随着页面的滑动距离比例随时改变位置 布局: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas

解析Android中实现滑动翻页之ViewFlipper的使用详解

1)View切换的控件-ViewFlipper介绍 ViewFilpper类继承于ViewAnimator类.而ViewAnimator类继承于FrameLayout. 查看ViewAnimator类的源码可以看出此类的作用主要是为其中的View切换提供动画效果.该类有如下几个和动画相关的方法. setInAnimation:设置View进入屏幕时候使用的动画.该方法有两个重载方法,即可以直接传入Animation对象,也可以传入定义的Animation文件的resourceID. setOut

Android中实现水平滑动(横向滑动)ListView示例

水平的ListView-HorizontalListView的使用 Android中ListView默认的是竖直方向的滑动,由于项目的需求,需要ListView是水平滑动的.有很多的方式可以实现,但是比较好的一种方式就是自己封装一个控件,使用方式和ListView的使用方式是一样的.需要完善的地方:获取到的图片大小没有处理.在界面上展示的是图片的原大小.为了更好的展示效果,应该压缩成统一的尺寸. HorizontalListView.java 代码如下: /** * 横向的ListView *

android配合viewpager实现可滑动的标签栏示例分享

复制代码 代码如下: package com.example.playtabtest.view; import com.example.playtabtest.R; import android.app.Activity;import android.content.Context;import android.support.v4.view.ViewPager;import android.support.v4.view.ViewPager.OnPageChangeListener;impor

Android使用ViewPager实现无限滑动效果

前言 其实仔细想一下原理还是挺简单的.无非是当我们滑动到最后一页,再向后滑动时定位到第一页;当我们滑动到第一页,再向前滑动时定位到最后一页. 但是,相信很多朋友都遇到过这个问题:视图的过度效果不自然. 小编也是通过百度和谷歌查找了很多解决方案,实验了很多方法,总结了一个相对不错的方法,接下来给各位分享下滑动效果.实现细节以及一些踩过的坑. 1.无限滑动效果(左右无限滑动) 事先准备好2张滑动图片(有想试验的小伙伴,自备图片啊,小编就不提供了...) 运行效果图(左右无限循环): 为了显示更加直观

Android利用ViewPager实现可滑动放大缩小画廊效果

画廊在很多的App设计中都有,如下图所示: 该例子是我没事的时候写的一个小项目,具体源码地址请访问https://github.com/AlexSmille/YingMi. 该画廊类似封面的效果,滑到中间的图片会慢慢变大,离开的View会慢慢的缩小,同时可设置滑动监听和点击监听. 网上有很多例子都是通过Gallery实现的,而上例的实现是通过ViewPager实现,解决了性能优化的问题,今天特此把它抽出来,封装一下,以便以后的方便使用.最终实现的效果如下: 使用方式 布局中添加该自定义控件 <R

Android使用ViewPager实现屏幕滑动效果

使用ViewPager实现屏幕滑动 从一个完整的屏幕移动到另一个屏幕的过程被称为屏幕滑动,在安装向导.幻灯片中应用广泛.下面介绍如何利用Android Support库的ViewPager来实现屏幕滑动. 创建View 创建一个在之后作为fragment的内容的布局文件,下面的例子中包含一个Textview,用来展示一些文字. <!-- fragment_screen_slide_page.xml --> <ScrollView xmlns:android="http://sc

Android使用ViewPager实现图片滑动预览效果

本文为大家分享了Android ViewPager实现图片滑动预览效果展示的具体代码,供大家参考,具体内容如下 效果图: 滑动前: 滑动后: 代码非常简单,实现起来很容易 xml代码: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/ap

Android中ViewPager带来的滑动卡顿问题解决要点解析

问题说明: 当SwipeRefreshLayout中放置了ViewPager控件,两者的滑动会相互冲突.具体表现为ViewPager的左右滑动不顺畅,容易被SwipeRefreshLayout拦截(即出现刷新的View). 问题原因: ViewPager本身是处理了滚动事件的冲突,它在横向滑动时会调用requestDisallowInterceptTouchEvent()方法使父控件不拦截当前的Touch事件序列.但是SwipeRefreshLayout的requestDisallowInter

Android之Viewpager+Fragment实现懒加载示例

我们在做应用开发的时候,一个Activity里面可能会以viewpager(或其他容器)与多个Fragment来组合使用.而ViewPager默认会缓存三页数据,即:Viewpager每加载一个Fragment,都会预先加载此Fragment左侧或右侧的Fragment.而如果每个fragment都需要去加载数据,或从本地加载,或从网络加载,那么在这个activity刚创建的时候就变成需要初始化大量资源,浪费用户流量不止,还造成卡顿,这样的结果,我们当然不会满意.那么,能不能做到当切换到这个fr

android开发教程之实现滑动关闭fragment示例

主要代码:(有注释) 复制代码 代码如下: package com.example.checkboxtest; import android.annotation.SuppressLint;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.os.Handler;import android.os.Message;import andr

Android编程开发ScrollView中ViewPager无法正常滑动问题解决方法

本文实例讲述了Android编程开发ScrollView中ViewPager无法正常滑动问题解决方法.分享给大家供大家参考,具体如下: 这里主要介绍如何解决ViewPager在ScrollView中滑动经常失效.无法正常滑动问题. 解决方法只需要在接近水平滚动时ScrollView不处理事件而交由其子View(即这里的ViewPager)处理即可,重写ScrollView的onInterceptTouchEvent函数,如下: package cc.newnews.view; import an

Android基于ViewPager实现的应用欢迎界面完整实例

本文实例讲述了Android基于ViewPager实现的应用欢迎界面.分享给大家供大家参考,具体如下: 有时候开发一个应用需要指导用户提示一些新功能,这样的欢迎界面的实现可以用一下方法 首先我们要用到ViewPager这个类,这个类是在Android-support-v4.jar中,网上搜一下就会有 现将这个包放到项目中,之后进行引用 ViewPager类个人理解就是一个容器,将你需要的图片资源放到他的Adapter中进行填充,这样我们就需要一个adapter,自定义一个adapter继承Pag