巧妙运用补间动画,自定义广告轮播CarouselView 2.0

  这是前一篇文章绘制的CarouselView的升级版,有兴趣的同学,可以去关注一下笔者前一篇文章。自定义广告图片轮播View——CarouselView

这次升级版相对于前文而已,有了一个功能上的飞跃主要区别体现如下:

  1. 构建方式更简单
  2. 提供更多的API拱用户自定义
  3. 提供5中不同应用场景的动画

  本文除了提供源码和API外,还会详细讲解如何利用补间动画以及ViewPager.PageTransformer实现花样轮播控件。如果对补间动画还存在疑惑的同学可以阅读笔者的另外一篇文章弥补一下。这次彻底搞懂Android补间动画

先看效果:

饿,不知道为什么,这里做成gif后异常的卡顿,实际效果肯定是如丝版顺滑的。

ANIM_ALPHA_PAGETRANS.gif

ANIM_LEFTLEAVE.gif

ANIM_ROTATEMAGIC.gif

ANIM_SCALEMAGIC.gif

ANIM_SCALERIGHTLEAVE.gif

CarouselView 2.0 如何使用:

ArrayList<CarouselView.CarouselBean> beans=new ArrayList<>();
beans.add(new CarouselView.CarouselBean(R.mipmap.img1,"第一张图"));
beans.add(new CarouselView.CarouselBean(R.mipmap.img2));
beans.add(new CarouselView.CarouselBean(R.mipmap.img3,"第三张图"));
beans.add(new CarouselView.CarouselBean(R.mipmap.img4,"第四张图"));
beans.add(new CarouselView.CarouselBean(R.mipmap.img5,"第五张图"));
beans.add(new CarouselView.CarouselBean(R.mipmap.img6));
carouselView.init(beans,CarouselView.ANIM_LEFTLEAVE);

  可见,使用方式还是非常简单的,简单的bean文件,支持传入图片和图片描述(可选),然后调用init方法初始化即可,第二个参数是动画,动画也是选传项,不设置动画则显示传统的轮播控件。   已经封装好5个动画提供给使用者使用。动画支持自定义。    在写文过程中,笔者发现,2.0页不是那么完善,比如没有提供网络图片的显示API,没有对外提供动画自定义的支持等等,这些内容笔者会考虑在3.0里提供,如果收到反馈和留言的话!!

CarouselView API:

void init(ArrayList<CarouselBean> beans,int anim): 控件初始化方法 参数一(必填):beans是图片的集合,包含图片和图片描述 。 参数二(选填):anim是动画参数,控件已封装了5个动画,对应5个常量,以ANIM开头。

void setIsRunningCarousel(boolean isRunning):控制轮播是否开启,默认为false,即不开启

void setIntervalsTime(int intervalsTime):控制轮播间隔时间,默认为5000ms

void setBottomViewBackGroundColor(int colorResource):设置底部描述文字布局的背景颜色,推荐#6000

void setPointVisible(boolean visible) 设置是否显示底部指示器,默认为true,即显示

public void setDescVisible(boolean visible):是否显示文字描述,默认为false,即不显示

关于轮播动画:

  从上面的效果图中,我们可以看到,实现的动画可以分为两大类。   第一类是只显示一个Item的动画,这类动画和传统的轮播没什么大的差异,只是多了一些补间动画修饰。   第二类是一页显示多个Item的动画,这样的轮播图看着更时尚也更高端,相比较于第一类,只是多了这样一段代码:

  /**
     * 当需要ViewPager一个界面显示多个Item的时候,调用改方法。
     */
    private void excisionPage(){
        FrameLayout.LayoutParams lp=new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
        lp.setMargins(120,40,120,40);
        viewPager.setLayoutParams(lp);
        viewPager.setClipChildren(false);
        frameLayout.setClipChildren(false);
        //设置Page间间距
        viewPager.setPageMargin(20);
        //设置缓存的页面数量
        if(beans.size()>5)viewPager.setOffscreenPageLimit(2);
    }

  上图中的viewpager是包裹在frameLayout里面的,我们给frameLayout添加margins,目的是给两遍的Item预留出显示的地方,然后设置viewpagerpagermargin,目的是将3个Item分开,item与item之间留有空白。最后也是最关键的为fragmeLayoutveiwPager设置属性setClipChildren(false),该属性能够让Android不去自动裁剪超出布局的部分,也就是我们ViewPager左右两遍的Item正常情况下是会被裁剪掉,不显示的,而设置该属性为false后能保证他们存活。

添加动画:

  既然要添加动画,首先我们肯定需要拿到在滑动的时候的一个可变化的值。ViewPager为我们提供了这样一个借口,我们实现VeiwPager.PageTransformer借口,然后添加进我们的ViewPager即可

 private void initAnim(int anim) {
        switch (anim){
            case ANIM_ALPHA_PAGETRANS:
                excisionPage();
                viewPager.setPageTransformer(true,new AlphaPageTransformer());
                break;
            case ANIM_SCALEMAGIC:
                excisionPage();
                viewPager.setPageTransformer(true,new ScaleMagic());
                break;
            case ANIM_ROTATEMAGIC:
                excisionPage();
                viewPager.setPageTransformer(true,new RotateMagic());
                break;
            case ANIM_LEFTLEAVE:
                viewPager.setPageTransformer(true,new LeftLeave());
                break;
            case ANIM_SCALERIGHTLEAVE:
                viewPager.setPageTransformer(true,new ScaleRightLeave());
                break;
            case ANIM_NORMAL:
            default:
                viewPager.setClipChildren(true);
                frameLayout.setClipChildren(true);
                break;
        }
    }

    /**
     * 当需要ViewPager一个界面显示多个Item的时候,调用改方法。
     */
    private void excisionPage(){
        FrameLayout.LayoutParams lp=new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
        lp.setMargins(120,40,120,40);
        viewPager.setLayoutParams(lp);
        viewPager.setClipChildren(false);
        frameLayout.setClipChildren(false);
        //设置Page间间距
        viewPager.setPageMargin(20);
        //设置缓存的页面数量
        if(beans.size()>5)viewPager.setOffscreenPageLimit(2);
    }

如何自定义ViewPager的PageTransformer:

PageTransformer的postion

  我们可以看到void transformPage(View view, float position)position的值主要需要关注得是position=-1、position=0、postion=1三个状态,当ViewPager的Item处于正中间时,他的postion=1。   从而我们只要确定3个点的状态,然后添加补间动画让他动起来的就可以了,不过我们也需要绘制在position<-1,postion>1的状态,否则在未滑动的时候,会空白。   综上所述,我们代码可以这样写:

@Override
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.
       } else if (position <= 0) { // [-1,0]
            
       } else if (position <= 1) { // (0,1]
            
       } else { // (1,+Infinity]
       // This page is way off-screen to the right.
      }
}

拿两个动画来举个例子:

  1. ANIM_SCALEMAGIC:

ANIM_SCALEMAGIC.gif

这个动画是非常实用的,我们看动画可以总结一下几点:

  1. 一个页面需要显示多个Item
  2. position=-1时(在左边时),是被缩小了的,有一个Scale动画,还有一个Alpha的渐变动画。postion=1(右边)时,同postion=-1; 有了上述总结,我们直接上代码:
    private class ScaleMagic implements ViewPager.PageTransformer {
        private static final float MIN_SCALE = 0.90f;
        private static final float MIN_ALPHA = 0.5f;
        @Override
        public void transformPage(View page, float position) {
            if (position < -1 || position > 1) {
                page.setAlpha(MIN_ALPHA);
                page.setScaleX(MIN_SCALE);
                page.setScaleY(MIN_SCALE);
            } else if (position <= 1) { // [-1,1]
                if (position < 0) {
                    float scaleX = 1 + 0.1f * position;
                    page.setScaleX(scaleX);
                    page.setScaleY(scaleX);
                } else {
                    float scaleX = 1 - 0.1f * position;
                    page.setScaleX(scaleX);
                    page.setScaleY(scaleX);
                }
                float scaleFactor = Math.max(MIN_ALPHA, 1 - Math.abs(position));
                page.setAlpha(MIN_ALPHA + (scaleFactor - MIN_ALPHA) / (1 - MIN_ALPHA) * (1 - MIN_ALPHA));
            }
        }
    }
  1. 我们设置两个常量,默认在左右边的渐变和缩放大小分别为50%和90%
  2. 设置(-infinite,-1)和(1,infinite) 的状态,即在左右两遍时,view十倍缩小了并且透明了
  3. 设置[-1,0)的状态,当postion=-1时,我们需要ScaleX=0.9f,postion=0时,ScaleX=1.0f。很显然,这只是一个二元一次方程,可得ScaleX=1+.01f*position。
  4. 设置(0,1]的状态,同上方式,我们可以计算出ScaleX=1-0.1f*position。
  5. 到此我们已经完成了Scale动画的绘制,然后是Aplha动画,从[-1,1]Item是一个从透明到不透明再到透明的过程,笔者采用了代码中的算法,其实可以同设置Scale动画一样,逐步设置。
  6. ANIM_SCALERIGHTLEAVE:

ANIM_SCALERIGHTLEAVE.gif

首先先总结一下这个动画的要点:

  1. 传统的轮播方式,同一页只显示一个Item
  2. 滑动时包含一个缩放动画
  3. 缩小时包含一个渐变动画
  4. 设置两个缩放和渐变的最小渐变值分别为0.85f和0.5f
  5. (-infinity,-1)(-,infinity)设置为全透明,因为一个页面值显示Item,所以为了方便,直接可以设置全透明
  6. (-1,1)分别设置位移动画、缩放动画以及渐变动画

源码分享:

package com.wusy.adv;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Created by XIAO RONG on 2018/8/8.
 */

public class CarouselView extends LinearLayout implements ViewPager.OnPageChangeListener {
    public static final int ANIM_NORMAL=0;
    public static final int ANIM_ALPHA_PAGETRANS=1;
    public static final int ANIM_SCALEMAGIC=2;
    public static final int ANIM_ROTATEMAGIC=3;
    public static final int ANIM_LEFTLEAVE=4;
    public static final int ANIM_SCALERIGHTLEAVE=5;
    private FrameLayout frameLayout;
    private LinearLayout ll_bottomview;
    private String TAG="CarouselView";
    private Context mC;
    private ViewPager viewPager;
    private LinearLayout ll_point;
    private TextView tv_desc;
    private ArrayList<ImageView> imageViews; //存放图片的集合
    private ArrayList<CarouselBean> beans;
    private int lastPosition;
    private boolean isRunning = false;
    private int intervalsTime=5000;
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0:
                    viewPager.setCurrentItem(viewPager.getCurrentItem()+1);
                    break;
            }
        }
    };
    public CarouselView(Context context) {
        this(context,null);
    }

    public CarouselView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public CarouselView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        LayoutInflater.from(context).inflate(R.layout.view_carousel, this);
        this.mC=context;
        findView();
    }
    private void findView(){
        viewPager=findViewById(R.id.view_carousel_viewpager);
        tv_desc=findViewById(R.id.view_carousel_tv_desc);
        ll_point=findViewById(R.id.view_carousel_ll_point);
        frameLayout=findViewById(R.id.view_carousel_framelayout);
        ll_bottomview=findViewById(R.id.view_carousel_ll_bottomview);
    }

    public void init(ArrayList<CarouselBean> beans,int anim){
        this.beans=beans;
        initView();
        initAnim(anim);
        initAdapter();
        startCarousel();
    }
    public void init(ArrayList<CarouselBean> beans){
        init(beans,ANIM_NORMAL);
    }
    /**
     * 是否开启轮播,默认不开启
     * @param isRunning
     */
    public void setIsRunningCarousel(boolean isRunning){
        this.isRunning=isRunning;
    }

    /**
     * 轮播间隔时间,默认为5000毫秒
     * @param intervalsTime
     */
    public void setIntervalsTime(int intervalsTime){
        this.intervalsTime=intervalsTime;
    }

    /**
     * 设置底部描述布局的背景颜色。推荐#6000
     * @param colorResource
     */
    public void setBottomViewBackGroundColor(int colorResource){
        ll_bottomview.setBackgroundColor(colorResource);
    }

    /**
     * 设置是否显示指示器,默认显示
     * @param visible
     */
    public void setPointVisible(boolean visible){
        if (visible) ll_point.setVisibility(VISIBLE);
        else ll_point.setVisibility(GONE);
    }

    /**
     * 设置是否显示文字描述。默认不显示
     * @param visible
     */
    public void setDescVisible(boolean visible){
        if (visible) tv_desc.setVisibility(VISIBLE);
        else tv_desc.setVisibility(GONE);
    }
    private void initAnim(int anim) {
        switch (anim){
            case ANIM_ALPHA_PAGETRANS:
                excisionPage();
                viewPager.setPageTransformer(true,new AlphaPageTransformer());
                break;
            case ANIM_SCALEMAGIC:
                excisionPage();
                viewPager.setPageTransformer(true,new ScaleMagic());
                break;
            case ANIM_ROTATEMAGIC:
                excisionPage();
                viewPager.setPageTransformer(true,new RotateMagic());
                break;
            case ANIM_LEFTLEAVE:
                viewPager.setPageTransformer(true,new LeftLeave());
                break;
            case ANIM_SCALERIGHTLEAVE:
                viewPager.setPageTransformer(true,new ScaleRightLeave());
                break;
            case ANIM_NORMAL:
            default:
                viewPager.setClipChildren(true);
                frameLayout.setClipChildren(true);
                break;
        }
    }

    /**
     * 当需要ViewPager一个界面显示多个Item的时候,调用改方法。
     */
    private void excisionPage(){
        FrameLayout.LayoutParams lp=new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
        lp.setMargins(120,40,120,40);
        viewPager.setLayoutParams(lp);
        viewPager.setClipChildren(false);
        frameLayout.setClipChildren(false);
        //设置Page间间距
        viewPager.setPageMargin(20);
        //设置缓存的页面数量
        if(beans.size()>5)viewPager.setOffscreenPageLimit(2);
    }
    /**
     * 初始化适配器
     */
    private void initAdapter() {
        ll_point.getChildAt(0).setEnabled(true);//初始化控件时,设置第一个小圆点为亮色
        tv_desc.setText(beans.get(0).getImgDescs()); //设置第一个图片对应的文字
        lastPosition=0;
        viewPager.setAdapter(new CarouseAdapter());
        Log.i(TAG,"initAdapter()完成");
    }

    /**
     * 初始化控件
     */
    private void initView(){
        viewPager.setOnPageChangeListener(this);
        imageViews=new ArrayList<>();
        ImageView imageView;
        View pointView;
        for (int i = 0; i < beans.size(); i++){
            //添加图片到集合中
            imageView = new ImageView(mC);
            imageView.setBackgroundResource(beans.get(i).getImgResource());
            imageViews.add(imageView);
            //加小白点,指示器(这里的小圆点定义在了drawable下的选择器中了,也可以用小图片代替)
            pointView = new View(mC);
            pointView.setBackgroundResource(R.drawable.carousel_point); //使用选择器设置背景
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(8, 8);
            if (i != 0){
                //如果不是第一个点,则设置点的左边距
                layoutParams.leftMargin = 10;
            }
            pointView.setEnabled(false); //默认都是暗色的
            ll_point.addView(pointView, layoutParams);
        }
        if(imageViews.size()>0) Log.i(TAG,"initView完成");
    }

    /**
     * 开启轮播
     */
    private  void startCarousel(){
        Log.i(TAG,"CarouselView轮播开启");
        new Thread(){
            @Override
            public void run() {
                while(isRunning){
                    try {
                        Thread.sleep(intervalsTime);
                        handler.sendEmptyMessage(0);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
    //页面滑动
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }
    //新的页面被选中
    @Override
    public void onPageSelected(int position) {
        //当前的位置可能很大,为了防止下标越界,对要显示的图片的总数进行取余
        int newPosition = position % beans.size();
        //设置描述信息
        if (beans.get(newPosition).getImgDescs()!=null)tv_desc.setText(beans.get(newPosition).getImgDescs());
        else tv_desc.setText("");
        //设置小圆点为高亮或暗色
        ll_point.getChildAt(lastPosition).setEnabled(false);
        ll_point.getChildAt(newPosition).setEnabled(true);
        lastPosition = newPosition; //记录之前的点
    }
    //页面滑动状态发生改变
    @Override
    public void onPageScrollStateChanged(int state) {

    }
    private class CarouseAdapter extends PagerAdapter{

        @Override
        public int getCount() {
            return Integer.MAX_VALUE;
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view==object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Log.i(TAG,"执行,position="+position);
            //从集合中获得图片
            int newPosition = position % imageViews.size(); //数组中总共有5张图片,超过数组长度时,取摸,防止下标越界
            ImageView imageView = imageViews.get(newPosition);
            //把图片添加到container中
            container.addView(imageView);
            //把图片返回给框架,用来缓存
            return imageView;
        }
        //销毁条目
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            //object:刚才创建的对象,即要销毁的对象
            container.removeView((View) object);
        }

    }
    public static class CarouselBean{
        private int imgResource;
        private String imgDescs;

        public int getImgResource() {
            return imgResource;
        }

        public void setImgResource(int imgResource) {
            this.imgResource = imgResource;
        }

        public String getImgDescs() {
            return imgDescs;
        }

        public void setImgDescs(String imgDescs) {
            this.imgDescs = imgDescs;
        }

        public CarouselBean(int imgResource, String imgDescs) {
            this.imgResource = imgResource;
            this.imgDescs = imgDescs;
        }
        public CarouselBean(int imgResource) {
            this.imgResource = imgResource;
        }
    }

    /**
     * 单纯渐变动画
     */
    private class AlphaPageTransformer implements ViewPager.PageTransformer{
        private float mMinAlpha = 0.5f;
        @Override
        public void transformPage(View view, float position) {
            float factor;
            if (position < -1) {
                view.setAlpha(mMinAlpha);
            } else if (position <= 1) { // [-1,1]
                if (position <= 0){ //[-1,0)
                    factor = mMinAlpha + (1 - mMinAlpha) * (1 + position);
                    view.setAlpha(factor);
                } else{//[0,1]
                    factor = mMinAlpha + (1 - mMinAlpha) * (1 - position);
                    view.setAlpha(factor);
                }
            }else { // (1,+Infinity]
                view.setAlpha(mMinAlpha);
            }
        }
    }
    /**
     * 渐变+缩放动画
     */
    private class ScaleMagic implements ViewPager.PageTransformer {
        private static final float MIN_SCALE = 0.90f;
        private static final float MIN_ALPHA = 0.5f;
        @Override
        public void transformPage(View page, float position) {
            if (position < -1 || position > 1) {
                page.setAlpha(MIN_ALPHA);
                page.setScaleX(MIN_SCALE);
                page.setScaleY(MIN_SCALE);
            } else if (position <= 1) { // [-1,1]
                if (position < 0) {
                    float scaleX = 1 + 0.1f * position;
                    page.setScaleX(scaleX);
                    page.setScaleY(scaleX);
                } else {
                    float scaleX = 1 - 0.1f * position;
                    page.setScaleX(scaleX);
                    page.setScaleY(scaleX);
                }
                float scaleFactor = Math.max(MIN_ALPHA, 1 - Math.abs(position));
                page.setAlpha(MIN_ALPHA + (scaleFactor - MIN_ALPHA) / (1 - MIN_ALPHA) * (1 - MIN_ALPHA));
            }
        }
    }

    /**
     * 旋转+渐变
     */
    private class RotateMagic implements ViewPager.PageTransformer {
        private float mMaxRotate = 15.0f;
        private float MIN_ALPHA = 0.7f;
        @Override
        public void transformPage(View view, float position) {
            if (position < -1) { // [-Infinity,-1)
                view.setRotation(mMaxRotate * -1);
                view.setPivotX(view.getWidth());
                view.setPivotY(view.getHeight());
            } else if (position <= 1) { // [-1,1]
                if (position <= 0){ //[0,-1]
                    view.setPivotX(view.getWidth() * (0.5f + 0.5f * (-position)));
                    view.setPivotY(view.getHeight());
                    view.setRotation(mMaxRotate * position);
                } else{//[1,0]
                    view.setPivotX(view.getWidth() * 0.5f * (1 - position));
                    view.setPivotY(view.getHeight());
                    view.setRotation(mMaxRotate * position);
                }
                float scaleFactor = Math.max(MIN_ALPHA, 1 - Math.abs(position));
                view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_ALPHA) / (1 - MIN_ALPHA) * (1 - MIN_ALPHA));
            } else { // (1,+Infinity]
                view.setRotation(mMaxRotate);
                view.setPivotX(view.getWidth() * 0);
                view.setPivotY(view.getHeight());
            }
        }
    }
    /**
     * 左边离开
     */
    private class LeftLeave implements ViewPager.PageTransformer {
        private final float MIN_SCALE = 0.75f;
        @Override
        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 <= 0) { // [-1,0]
                // Use the default slide transition when moving to the left page
                view.setAlpha(1);
                view.setTranslationX(0);
                view.setScaleX(1);
                view.setScaleY(1);

            } else if (position <= 1) { // (0,1]
                // Fade the page out.
                view.setAlpha(1 - position);

                // Counteract the default slide transition
                view.setTranslationX(pageWidth * -position);

                // Scale the page down (between MIN_SCALE and 1)
                float scaleFactor = MIN_SCALE
                        + (1 - MIN_SCALE) * (1 - Math.abs(position));
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);

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

    }
    /**
     * 缩小右边离开
     */
    private class ScaleRightLeave implements ViewPager.PageTransformer {
        private static final float MIN_SCALE = 0.85f;
        private static final float MIN_ALPHA = 0.5f;
        @Override
        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();
            int pageHeight = view.getHeight();

            Log.e("TAG", view + " , " + position + "");

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

            } else if (position <= 1) //a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0
            { // [-1,1]
                // Modify the default slide transition to shrink the page as well
                float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
                float vertMargin = pageHeight * (1 - scaleFactor) / 2;
                float horzMargin = pageWidth * (1 - scaleFactor) / 2;
                if (position < 0) {
                    view.setTranslationX(horzMargin - vertMargin / 2);
                } else {
                    view.setTranslationX(-horzMargin + vertMargin / 2);
                }

                // Scale the page down (between MIN_SCALE and 1)
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);

                // Fade the page relative to its size.
                view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)
                        / (1 - MIN_SCALE) * (1 - MIN_ALPHA));

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏儿童编程

《动物魔法学校》儿童学编程Scratch之“外观”部分

导读:本文通过一个案例《动物魔法学校》来学习Scratch语言的“外观”部分。之后通过一系列其他功能的综合运用对作品功能进行了扩展。

18840
来自专栏儿童编程

天干地支五行八卦的对应关系

18890
来自专栏FSociety

SQL中GROUP BY用法示例

GROUP BY我们可以先从字面上来理解,GROUP表示分组,BY后面写字段名,就表示根据哪个字段进行分组,如果有用Excel比较多的话,GROUP BY比较类...

5.1K20
来自专栏儿童编程

儿童创造力教育与编程教育的碰撞——MIT雷斯尼克教授最新理论梗概

儿童编程教育已经在我国各一线二线城市疯狂出现,颇有“烂大街”的趋势。我们不禁要问很多很多问题:

21870
来自专栏儿童编程

我不是算命先生,却对占卜有了疑惑——如何论证“占卜前提”的正确与否

事出有因,我对《周易》感兴趣了很多年。只是觉得特别有趣,断断续续学习了一些皮毛。这几天又偶然接触到了《梅花易数》,觉得很是精彩,将五行八卦天干地支都串联了起来。...

14410
来自专栏Ken的杂谈

【系统设置】CentOS 修改机器名

17630
来自专栏haifeiWu与他朋友们的专栏

复杂业务下向Mysql导入30万条数据代码优化的踩坑记录

从毕业到现在第一次接触到超过30万条数据导入MySQL的场景(有点low),就是在顺丰公司接入我司EMM产品时需要将AD中的员工数据导入MySQL中,因此楼主负...

27240
来自专栏儿童编程

什么样的人生才是有意义的人生——没有标准的标准答案

【导读】其实我们可以跳出这个小圈圈去更加科客观地看一下这个世界。在夜晚的时候我们仰望天空,浩瀚的宇宙中整个地球只是一粒浮尘,何况地球上一个小小的人类?在漫长的历...

1.7K50
来自专栏儿童编程

声音功能让儿童编程更有创造性

导读:Scratch中声音功能非常强大,除了常规的音效,你甚至可以模拟各种乐器的各个发音、设置节拍、休止……如果你愿意,甚至可以用它创作一个交响乐。我们可以引导...

13540
来自专栏儿童编程

一张图理清《梅花易数》梗概

学《易经》的目的不一定是为了卜卦,但是了解卜卦绝对能够让你更好地了解易学。今天用一张思维导图对《梅花易数》的主要内容进行概括,希望能够给学友们提供帮助。

31040

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励