ViewPager动画详解

GitHub:lightSky

微博:    light_sky, 即时分享最新技术,欢迎关注

前言

前两天看到鲍永章分享的Great
animations with PageTransformer
以及农民伯伯分享的Create
ViewPager transitions
 文章,都是通过ViewPager来实现酷炫的动画,而现在的App中ViewPager的动画使用也非常的广泛。正好最近一直研究动画,那么就趁热打铁,分析一下相关的开源库吧。本篇文章介绍的ViewPager动画,可以分为两类,第一类是针对于ViewPager的界面滑动动画(这个是PageTransformer的真正用途),分析并比较了AndroidImageSlider和JazzyViewPager两种实现,第二类是对ViewPager中的内容进行动画处理,这个是这个是PageTransformer的巧妙应用,处理好了可以达到很棒的交互效果,示例是Yahoo天气的视差效果。

ViewPager动画的实现原理

从3.0开始,ViewPager开始支持自定义切换动画,暴露的接口为PageTransformer,因此只要实现PageTransformer接口和其唯一的方法transformPage(View view, float position)即可。

/**
   * A PageTransformer is invoked whenever a visible/attached page is scrolled.
   * This offers an opportunity for the application to apply a custom transformation
   * to the page views using animation properties.
   *
   * <p>As property animation is only supported as of Android 3.0 and forward,
   * setting a PageTransformer on a ViewPager on earlier platform versions will
   * be ignored.</p>
   */
  public interface PageTransformer {
      /**
       * Apply a property transformation to the given page.
       *
       * @param page Apply the transformation to this page
       * @param position Position of page relative to the current front-and-center
       *                 position of the pager. 0 is front and center. 1 is one full
       *                 page position to the right, and -1 is one page position to the left.
       */
      public void transformPage(View page, float position);
 }
  • 参数position

    给定界面的位置相对于屏幕中心的偏移量。在用户滑动界面的时候,是动态变化的。那么我们可以将position的值应用于setAlpha(), setTranslationX(), or setScaleY()方法,从而实现自定义的动画效果。

    另外在ViewPager滑动时,内存中存活的Page都会执行transformPage方法,在滑动过程中涉及到两个Page,当前页和下一页,而它们的position值是相反的(因为是相对运动,一个滑入一个滑出),比如,页面A向右滑动到屏幕一半,页面B也正好处于一半的位置,那么A和B的position为:0.5 和 -0.5

    position == 0 :当前界面位于屏幕中心的时候

    position == 1 :当前Page刚好滑出屏幕右侧

    position == -1 :当前Page刚好滑出屏幕左侧

AndroidImageSlider动画库解析

要说到动画库,肯定会想到代码家,没错,代码家也开源了一个ViewPager效果的库:AndroidImageSlider ,我们就来分析下这个库的实现。AndroidImageSlider除了基本的page动画外,也支持用户为Page内容添加自定义的动画,比如下面描述框的动画。

AndroidImageSlider兼容性的实现原理

因为API 11才开始支持PagerTransformer. 这里面修改了Android系统的ViewPager,名为ViewPagerEx,ViewPager里面有一段if逻辑判断是否在3.0以上使用PagerTransformer。因为PagerTransformer动画效果的实现依赖了PropertyViewAnim。但代码家的这个库使用NineOldAndroids实现了向3.0之前的兼容。因此就把这个if条件去掉了,其它部分都没变。

/**
 * @author daimajia : I just remove the if condition in setPageTransformer() to make it compatiable with Android 2.0+
 * of course, with the help of the NineOldDroid.
 * Thanks to JakeWharton.
 * http://github.com/JakeWharton/NineOldAndroids
 */

AndroidImageSlider的总体设计

  • BaseTransformer

    所有Transformer的基类,实现了ViewPagerEx.PageTransformer接口以及transformPage方法,并提供了onPreTransform(View view, float position)、onPostTransform(View view, float position)、onTransform(View view, float position);

    分别在transformPage前后调用,用来处理为每一次的执行动画前的准备和结束动作,比如还原所有的动画状态。

  • BaseAnimationInterface:

    ViewPagerEx执行Transformer动画的时候注入一些自己的动画。你需要实现该接口,然后实现以下4个方法,获取SlideView中的View,实现自己的动画。比如底部的DescriptionText动画DescriptionAnimation 出现时的动画就是onNextItemAppear中添加的,你可以点入,看下源码

    onPrepareCurrentItemLeaveScreen(View current)

    onPrepareNextItemShowInScreen(View next)

    onCurrentItemDisappear(View view)

    onNextItemAppear(View view)

而这4个方法的调用是在BaseTransformer中。BaseTransformer统一管理了Page滑动时的所有动画。为了获取这4个方法的调用时机,也是煞费苦心啊,先说下思路:

因为ViewPager滑动的时候transformPage方法是实时调用的,这里获取最初两次调用时传入的position进行比较。通过一个HashMap<view, arraylist>来维护不同pageView的多个position。但这里为了优化,只取前两个position做比较。

先判断起始滑动的方向,然后再判断下一次滑动的方向,两次结果作差来判断到底哪个page要离开界面还是进入界面。

确定2个界面的4种临界状态

if(mCustomAnimationInterface != null){
            if(h.containsKey(view) == false || h.get(view).size() == 1){
                if(position > -1 && position < 1){
                    if(h.get(view) == null){
                        h.put(view,new ArrayList<Float>());//为每个View创建一个List,来存储偏移分数position
                    }
                    h.get(view).add(position);//向指定的View中添加偏移分数
                    if(h.get(view).size() == 2){
                        float zero = h.get(view).get(0);
                        float cha = h.get(view).get(1) - h.get(view).get(0);//当前滑动的位移偏移量分数差: newfraction - oldfraction
                        if(zero > 0){//起始时,向左滑动,当前Page中心位于屏幕中心左侧
                            //判断滑动趋势,如果继续向左侧滑动,position从0到1越来越大 newfraction > oldfraction
                            if(cha > -1 && cha < 0){//向右侧滑动
                                //in
                                mCustomAnimationInterface.onPrepareNextItemShowInScreen(view);//下一个Page将要进入屏幕
                            }else{//cha > 0 继续向左侧滑动
                                //out
                                mCustomAnimationInterface.onPrepareCurrentItemLeaveScreen(view);//当前Page将要离开屏幕
                            }
                        }else{//起始时,向右滑动,当前Page中心位于屏幕中心右侧
                            //判断滑动趋势,如果继续向右侧滑动,position从0到-1越来越小 newfraction < oldfraction
                            if(cha > -1 && cha < 0){//负值,继续向右滑动,因此当前page将要滑出屏幕
                                //out
                                mCustomAnimationInterface.onPrepareCurrentItemLeaveScreen(view);//当前Page将要离开屏幕
                            }else{//向左滑动
                                //in
                                mCustomAnimationInterface.onPrepareNextItemShowInScreen(view);//下一个Page将要离开屏幕
                            }
                        }
                    }
                }
            }
        }
 boolean isApp,isDis;
    /**
     * Called each {@link #transformPage(View, float)} call after {@link #onTransform(View, float)} is finished.
     *
     * @param view
     * @param position
     */
    protected void onPostTransform(View view, float position) {
        if(mCustomAnimationInterface != null){
            if(position == -1 || position == 1){//当前界面刚好完全移除界面
                mCustomAnimationInterface.onCurrentItemDisappear(view);
                isApp = true;
            }else if(position == 0){
                mCustomAnimationInterface.onNextItemAppear(view);//下一个Page刚好完全显示
                isDis = true;
            }
            if(isApp && isDis){
                h.clear();
                isApp = false;
                isDis = false;
            }
        }
    }
  • BaseSliderView

    该类就是SlideView的基类,持有SlideView的一些公共方法,比如设置SliderView的image资源的方法image(File file),图片加载异常和失败的处理,empty(URL)用于展示,errorDisappear(boolean disappear)。这种思想和一个EmptyView有些类似,在我公司的项目也是使用了这种方式,比如通常一个ListView的界面,会有一个包装后的progressbar(包含各种情况的处理)来显示进度,当加载失败的时候,或者无数据的时候,可以调用该progressbar身上的方法,去决定显示何种布局。使用起来很方便。当然如果你的SliderView更复杂,你可以通过实现BaseSliderView,然后实现自己的SliderView。

下面两个类就是切换的View:

DefaultSliderView:实现了BaseSliderView,该View默认就是一张图片

TextSliderView:带有图片和描述性文字的View

  • Sliderlayout:

    一个控制中心,将InfiniteViewPager,PageIndicator,粘合在一起,控制动画的样式,ViewPager轮循的播放。

addSlider:向ViewPager中添加一个SlideView

startAutoCycle:启动轮播

pauseAutoCycle:停止轮播

setDuration: 轮播间隔

setPagerTransformer 为ViewPager设置自定义的PageTransformer

onInterceptTouchEvent 在用户手势按下的时候,就停止轮循

Note:

这里在onInterceptTouchEvent中处理而不能再onTouchEvent中处理。因为SlideView会消费掉点击事件,事件被消费了,没法返回给SlideLayout的onTouchEvent中。

OK,总体设计弄清楚后,剩下来就是动画中最核心的部分了,就是动画效果的实现,这里只简单的介绍Accordion动画的实现,其它的大家可以自己分析。关于PropertyView动画的使用,可以参考我的另一篇文章:PropertyAnim实际应用

Accordion

public class AccordionTransformer extends BaseTransformer {
    @Override
    protected void onTransform(View view, float position) {
        ViewHelper.setPivotX(view,position < 0 ? 0 : view.getWidth());
        ViewHelper.setScaleX(view,position < 0 ? 1f + position : 1f - position);
    }
}

代码家在README中注明了Thanks JazzyViewPager,开始没注意,后来看JazzyViewPager的源码时候偶然发现AndroidImageSlider的一些实现的灵感是来自JazzyViewPager项目。不过JazzyViewPager的实现方式略显复杂,没有使用PageTransformer接口,而是使用了OnPageChangeListener接口的onPageScrolled方法。

下面简单的看下JazzyViewPager库的动画实现,它将positionOffset作为参数控制。由于positionOffset的值为[0,1),所以就需要分别处理正负的情况。另外JazzyViewPager是通过维护一个LinkedHashMap来持有Page的引用。在Adapter添加界面的时候,会调用JazzyViewPager的 setObjectForPosition(Object obj, int position) 方法存入到集合中去。然后在onPageScrolled方法中再根据position获取当前Page的前一个mLeft和后一个mRight界面,分别对前后两个界面添加动画。

两种方式的关键参数区别

onPageScrolled(int position, float positionOffset, int positionOffsetPixels)方法的参数:

/**
         * This method will be invoked when the current page is scrolled, either as part
         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
         *
         * @param position Position index of the first page currently being displayed.
         *                 Page position+1 will be visible if positionOffset is nonzero.
         * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
         * @param positionOffsetPixels Value in pixels indicating the offset from position.
         */
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);

下面是打印的PageTransformer接口的transformPage时position的值:相邻两界面的绝对值的和为1.而正负则表示了滑入和滑出状态

12-15 21:03:13.025    I/System.out﹕ transformPage----------------------    -0.43611112
       12-15 21:03:13.025    I/System.out﹕ transformPage----------------------    0.5638889

12-15 21:03:13.045    I/System.out﹕ transformPage----------------------    -0.38055557
       12-15 21:03:13.045    I/System.out﹕ transformPage----------------------    0.61944443

12-15 21:03:13.045    I/System.out﹕ transformPage----------------------    -0.37777779
       12-15 21:03:13.045    I/System.out﹕ transformPage----------------------    0.62222224

12-15 21:03:13.055    I/System.out﹕ transformPage----------------------    -0.32916668
       12-15 21:03:13.055    I/System.out﹕ transformPage----------------------    0.67083335

12-15 21:03:13.065    I/System.out﹕ transformPage----------------------    -0.32222223
       12-15 21:03:13.065    I/System.out﹕ transformPage----------------------    0.67777777

12-15 21:03:13.075    I/System.out﹕ transformPage----------------------    -0.27916667
       12-15 21:03:13.075    I/System.out﹕ transformPage----------------------    0.72083336

onPageScrolled方法的positionOffset的值为 [0, 1) ,而PageTransformer接口的transformPage(View page, float position) 已经标好了正负值(滑入和滑出),如果你的动画正好是相对的,那么用transfromPage就简单的多。

我们取同一种动画效果Cube来比较一下JazzyViewPager和AndroidImageSlider两者的实现:

JazzyViewPager部分源码

	@Override
	public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

		...
		float effectOffset = isSmall(positionOffset) ? 0 : positionOffset;
		mLeft = findViewFromObject(position);
		mRight = findViewFromObject(position+1);
		switch (mEffect) {
			case Standard:
				break;
			...
			case animateCube:
				animateCube(mLeft, mRight, effectOffset);
				break;
		}
	}
	...
	private void animateCube(View left, View right, float positionOffset, boolean in) {
		if (mState != State.IDLE) {
			if (left != null) {
				manageLayer(left, true);
				mRot = (in ? 90.0f : -90.0f) * positionOffset;
				ViewHelper.setPivotX(left, left.getMeasuredWidth());
				ViewHelper.setPivotY(left, left.getMeasuredHeight()*0.5f);
				ViewHelper.setRotationY(left, mRot);
			}
			if (right != null) {
				manageLayer(right, true);
				mRot = -(in ? 90.0f : -90.0f) * (1-positionOffset);
				ViewHelper.setPivotX(right, 0);
				ViewHelper.setPivotY(right, right.getMeasuredHeight()*0.5f);
				ViewHelper.setRotationY(right, mRot);
			}
		}
	}
	public void setObjectForPosition(Object obj, int position) {//每次Adapter实例化View的时候,调用该方法,将实例化的View存入集合
			mObjs.put(Integer.valueOf(position), obj);
		}

	public View findViewFromObject(int position) {//根据position从集合中获取到对应的View
			Object o = mObjs.get(Integer.valueOf(position));
			if (o == null) {
				return null;
			}
			PagerAdapter a = getAdapter();
			View v;
			for (int i = 0; i < getChildCount(); i++) {
				v = getChildAt(i);
				if (a.isViewFromObject(v, o))
					return v;
			}
			return null;
		}
	....
}

AndroidIamgeSlider中的CubeIn:

public class CubeInTransformer extends BaseTransformer {
	@Override
	protected void onTransform(View view, float position) {
		// Rotate the fragment on the left or right edge
        ViewHelper.setPivotX(view,position > 0 ? 0 : view.getWidth());
        ViewHelper.setPivotY(view,0);
        ViewHelper.setRotation(view,-90f * position);
	}
}

JazzyViewPager:CubeIn上面代码中已经贴出:

if (left != null) {
	...
	mRot = (in ? 90.0f : -90.0f) * positionOffset;
	...
	}
if (right != null) {
	mRot = -(in ? 90.0f : -90.0f) * (1-positionOffset);
}

可以精简为:

positionOffset * value
-(1-positionOffset) * value

与从上面的transformPage打印的position的值再比较下

12-15 21:03:13.075    I/System.out﹕ transformPage----------------------    -0.27916667
       12-15 21:03:13.075    I/System.out﹕ transformPage----------------------    0.72083336

结论:

发现transformPage已经帮我们处理好了一切,直接用。我们可以根据正负符号来判断滑入和滑出的View(不用像JazzyViewPager那样去维护一个集合了),从而针对滑入滑出做出不同或相对的的动画。最简单的,两个界面如果是简单的相对动画(滑入对滑出),则什么都不用处理,直接用就行了,就像下面介绍的Yahoo视差的实现一样,具体可以看下面的讲解。

大家仔细看下相同的动画效果的处理方式,CubeInTransformer不用单独处理上一个和下一个界面,而只管根据position的正负判断当前Page和下一个Page去自定义不同的动画即可。

所以可以把AndroidImageSlider中的一些动画效果看做是JazzyViewPager的精简版本。

对于ViewPager如何帮我们处理View的呢?可以看下源码:

 protected void onPageScrolled(int position, float offset, int offsetPixels) {
...
if (mPageTransformer != null) {
            final int scrollX = getScrollX();
            final int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                final View child = getChildAt(i);
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                if (lp.isDecor) continue;
                final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth();
                mPageTransformer.transformPage(child, transformPos);
            }
        }
...
 }

小结

上面主要介绍了ViewPager的Page的滑动动画,两种实现方式:

PageTransformer.transformPage方式:在执行onPageScrolled方法的时候,会遍历ViewPager的所有View,并执行其transformPage方法。position是已经处理好的(方向和值)

onPageScrolled方式:略显复杂,因为没法拿到View,还要自己去维护一个View集合,并且positionOffset的限制,需要自己去处理不同View的position : PageA:position , PageB:-(1-position)。

为ViewPager的Page内容添加动画,实现炫酷的交互效果

Tholotis

实现原理

为Page内部的View处理不同的平移速度,达到视差的效果,作者的代码:

public void transformPage(View view, float position) {
    int pageWidth = view.getWidth();

    if (position < -1) { // [-Infinity,-1)
        // This page is way off-screen to the left.
        view.setAlpha(0);

    } else if (position <= 1) { // [-1,1]

        mBlur.setTranslationX((float) (-(1 - position) * 0.5 * pageWidth));
		mBlurLabel.setTranslationX((float) (-(1 - position) * 0.5 * pageWidth));

		mDim.setTranslationX((float) (-(1 - position) * pageWidth));
		mDimLabel.setTranslationX((float) (-(1 - position) * pageWidth));

		mCheck.setTranslationX((float) (-(1 - position) * 1.5 * pageWidth));
		mDoneButton.setTranslationX((float) (-(1 - position) * 1.7 * pageWidth));
		// The 0.5, 1.5, 1.7 values you see here are what makes the view move in a different speed.
		// The bigger the number, the faster the view will translate.
		// The result float is preceded by a minus because the views travel in the opposite direction of the movement.

		mFirstColor.setTranslationX((position) * (pageWidth / 4));

		mSecondColor.setTranslationX((position) * (pageWidth / 1));

		mTint.setTranslationX((position) * (pageWidth / 2));

		mDesaturate.setTranslationX((position) * (pageWidth / 1));
		// This is another way to do it

    } else { // (1,+Infinity]
        // This page is way off-screen to the right.
        view.setAlpha(0);
    }
}

GitHub上类似的效果

https://github.com/prolificinteractive/ParallaxPager

https://github.com/flavienlaurent/discrollview

这两个项目都封装成了库,使用的时候也简单,但一般我们可以通过ViewPager.PageTransformer来实现这样的效果,从上面AndroidImageSlider与JazzyViewPager的对比中也能看到,PageTransformer的实现方式更简单。而且ViewPager的动画库也很多,比如上面的JazzyViewPager。你只需把某一个动画效果的transformPage方法的逻辑拿来就可用,当然如果你的需求更复杂,或者ViewPager实现起来较麻烦,你可以考虑上面的两个项目,扩展自己的思维。

JazzyViewPager:

https://github.com/jfeinstein10/JazzyViewPager/blob/master/lib/src/com/jfeinstein/jazzyviewpager/JazzyViewPager.java

https://github.com/prolificinteractive/ParallaxPager

https://github.com/flavienlaurent/discrollview

Yahoo天气

原理很简单,只是这次处理的动画对象是背景图片,减慢其平移的速度,而ViewPager的内容正常移动,从而达到视差的效果。

public class ParallaxPageTransformer implements ViewPager.PageTransformer {

		public void transformPage(View view, float position) {

			int pageWidth = view.getWidth();

			 if (position < -1) { // [-Infinity,-1)
		            // This page is way off-screen to the left.
		            view.setAlpha(1);

		        } else if (position <= 1) { // [-1,1]

		        	dummyImageView.setTranslationX(-position * (pageWidth / 2)); //Half the normal speed

		        } else { // (1,+Infinity]
		            // This page is way off-screen to the right.
		            view.setAlpha(1);
				}

		}
	}

OK,本来想自己写,但刚巧在GitHub上发现了一个:ParallaxPagerTransformer ,并提供了APK ,实现了Yahoo天气的效果,但多了一些缩放的效果,将缩放的代码注释掉就和Yahoo天气的效果完全一样了。另外想clone到本地的朋友注意了,由于作者的AndroidStudio版本太老,导入的时候你需要做一些处理。

作者把该Transformer抽取出来,做为了一个lib,就一个类,核心代码很简单,说明ViewPager.PageTransformer接口很强大啊:

@Override
  public void transformPage(View view, float position) {
      View parallaxView = view.findViewById(id);
      if (parallaxView != null) {
          if (position > -1 && position < 1) {
              float width = parallaxView.getWidth();
              parallaxView.setTranslationX(-(position * width * speed));
              float sc = ((float)view.getWidth() - border)/ view.getWidth();
              if (position == 0) {//这里处理了缩放的效果,去掉即和Yahoo天气的效果一样
                  view.setScaleX(1);
                  view.setScaleY(1);
              } else {
                  view.setScaleX(sc);
                  view.setScaleY(sc);
              }
          }
      }
  }

看了上面的实现,大家应该知道如何去实现类似的交互动画了,而且现在的App导航页中,也越来越多的使用到了这样的交互,作者在文章还列举了News Digest的导航页,有了思路,实现起来应该就不难了,第一、三页的动画上面已经介绍过,对于第二页,其实就是一个旋转动画。实时的旋转可以通过实时变化的position来处理。

类似的项目

https://github.com/andraskindler/parallaxviewpager

总结:

整篇文章介绍的东西其实很简单,只是以前没有研究过ViewPager.PageTransformer,使用简单,但功能强大,position参数在动画处理中相当重要,因为是实时的百分比,所以省去了自己不少计算,如果你需要为ViewPager自定义动画,那么选择PageTransformer,对于本文的第二类巧妙动画效果的介绍,看具体情况决定是否使用PageTransformer,如果position能很方便帮助动画的计算,那是最好的,如果不是那么你完全可以使用onPageScrolled来处理,源码中也可看到,PageTransformer就是在onPageScroll中调用的。

使用时要注意,它只支持3.0以上的系统。如果要兼容,可以参考上面AndroidImageSlider的兼容实现。在文章中也插入了不少ViewPager动画项目的链接,也许不是使用PageTransformer,但也是一种思路的扩展,供大家参考。下一篇文章,我会介绍Fragment的动画,大家敬请期待。

参考文献:

官方文档

Great
animations with PageTransformer

Create ViewPager transitions

GitHub上相关的ViewPager动画的项目

https://github.com/daimajia/AndroidImageSlider

https://github.com/inovex/ViewPager3D

轮循的ViewPager

https://github.com/antonyt/InfiniteViewPager

https://github.com/JakeWharton/salvage

https://github.com/Trinea/android-auto-scroll-view-pager

VerticalViewPager

https://github.com/JakeWharton/Android-DirectionalViewPager

https://github.com/LambergaR/VerticalViewPager

https://github.com/VenomVendor/AutoNotifyViewPager

https://github.com/Dreddik/AndroidTouchGallery

特效的ViewPager

https://github.com/kmshack/Android-ParallaxHeaderViewPager

https://github.com/andraskindler/parallaxviewpager

https://github.com/MoshDev/BackgroundViewPager

与ViewPager一起使用的导航:

https://github.com/astuetz/PagerSlidingTabStrip (不支持TextView颜色的变化)

https://github.com/jpardogo/PagerSlidingTabStrip (支持TextView颜色变化)

https://github.com/DSofter/SmoothTabIndicator

FragmentAnim

https://github.com/DesarrolloAntonio/FragmentTransactionExtended

时间: 2024-09-30 16:09:40

ViewPager动画详解的相关文章

Android实习札记(6)---ViewPager使用详解

Android实习札记(6)---ViewPager使用详解                                    --转载请注明出处:coder-pig 札记(5)中介绍了Fragment构建简单的底部导航栏,在结尾的时候说要在下一节中,结合Viewpager 实现进入软件时的引导界面,说到ViewPager,很多朋友都用过,不过只知道粘贴复制,连一些基本的 东西都不知道,那是不行的,在本节中就先讲下ViewPager的一些基本概念吧! 1.首先ViewPager在哪个包下?

Android:ViewPager扩展详解——带有导航的ViewPagerIndicator(附带图片缓存,异步加载图片)

大家都用过viewpager了, github上有对viewpager进行扩展,导航风格更加丰富,这个开源项目是ViewPagerIndicator,很好用,但是例子比较简单,实际用起来要进行很多扩展,比如在fragment里进行图片缓存和图片异步加载. 下面是ViewPagerIndicator源码运行后的效果,大家也都看过了,我多此一举截几张图: 下载源码请点击这里 ===========================================华丽的分割线==============

android动画详解三 动画API概述

· 属性动画与view动画的不同之处 view动画系统提供了仅动画View 对象的能力,所以如果你想动画非View 对象,你就要自己实现代码. view动画系统实际上还被强制仅能对 View 的少数属性进行动画,比如缩放和旋转,而不能对背景色进行. view动画的另一个坏处是它仅修改View的绘制位置,而不是View的实际位置.例如,如果你动画一个移动穿越屏幕,button的绘制位置是正确的,但实际你可以点击它的位置却没有变,所以你必须去实现你自己的逻辑来处理它. 使用属性动画系统时,这个限制被

iOS动画详解(学习动画看这一篇就够了)

iOS动画详解(学习动画看这一篇就够了) 一.基础知识 CAAnimation.png 二.CABasicAnimation 1. 动画的属性和解释 2.属性值的解释 repeatCount : 如果在swift中需要一直不断重复:Float.infinity,OC:HUGE_VALF timingFunction: timingFunction.png kCAMediaTimingFunctionLinear--在整个动画时间内动画都是以一个相同的速度来改变.也就是匀速运动.一个线性的计时函数

android动画详解四 创建动画

· 使用ValueAnimator进行动画 通过指定一些int, float或color等类型的值的集合,ValueAnimator 使你可以对这些类型的值进行动画.你需通过调用ValueAnimator 的某个工厂方法来获得一个ValueAnimator 对象,比如:ofInt(), ofFloat(), 或 ofObject().例如: ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f); animation.setDuration

Animation动画详解(十一)——layoutAnimation与gridLayoutAnimation

前言:人或许天生是懒惰的,明知道的不足,却不努力弥补. 相关博客: 1.<Animation 动画详解(一)--alpha.scale.translate.rotate.set的xml属性及用法> 2.<Animation动画详解(二)--Interpolator插值器> 3.<Animation动画详解(三)-- 代码生成alpha.scale.translate.rotate.set及插值器动画> 4.<Animation动画详解(四)--ValueAnima

&quot;MindManager&quot;学习iOS系列之&quot;CAAnimation-核心动画&quot;详解,让你的应用“动”起来。

"MindManager"学习iOS系列之"CAAnimation-核心动画"详解,思维导图内展示了CAAnimation-核心动画的大多数基本功能和知识,每个part都有代码讲解,展示出CAAnimation-核心动画的清晰轮廓,编者提供了"JPG"."SWF"."PDF"."Word"."Mmap"格式的源文件供给使用.注意:JPG格式仅为图片总览,SWF格式使用

Android Animation动画详解(二): 组合动画特效

前言 上一篇博客Android Animation动画详解(一): 补间动画 我已经为大家介绍了Android补间动画的四种形式,相信读过该博客的兄弟们一起都了解了.如果你还不了解,那点链接过去研读一番,然后再过来跟着我一起学习如何把简单的动画效果组合在一起,做出比较酷炫的动画特效吧. 一. 动画的续播 如题,大家想想,如果一个页面上包含了许多动画,这些动画要求按顺序播放,即一个动画播放完成后,继续播放另一个动画,使得这些动画具有连贯性.那该如何实现呢? 有开发经验或者是逻辑思维的人肯定会想,对

Animation动画详解(五)——ValueAnimator高级进阶(一)

前言:唯有脚踏实地,才能厚积薄发,未来只属于为梦想而奋斗的人们,今天的你决定未来的自己. 上一篇给大家介绍了ValueAnimator的大部分函数的用法,不过还都是些简单的用法,这篇我们带大家来看看有关加速器.animator和keyFrame的知识. 一.插值器 插值器,也叫加速器:有关插值器的知识,我在<Animation动画详解(二)--Interpolator插值器>中专门讲过,大家可以先看看这篇文章中各个加速器的效果.这里再讲一下什么是插值器.我们知道,我们通过ofInt(0,400