美文网首页
Android 一个简单的无限循环、带特效的ViewPager

Android 一个简单的无限循环、带特效的ViewPager

作者: DON_1007 | 来源:发表于2019-12-07 16:35 被阅读0次

实现效果图

viewpagerdemo.gif

这个效果是用ViewPager实现的,实现方式为ViewPager + Fragment + PageTransformer。主要功能点有

  • ViewPager+Fragment无限循环,ViewPager的无限循环比较简单的有以ViewPager+View的方式实现,这里使用ViewPager+Fragment是因为FragmentView有更多的方法,更多的属性,以及生命周期以便于灵活的、高效的完成开发任务
  • 通过PageTransformer实现左右两张图片的显示及特效添加
  • 动态修改ViewPager的滑动速度
  • 动态控制ViewPager对连续长按遥控器左右键的事件响应

一、ViewPager+Fragment无限循环实现

无限循环功能点的实现主要工作在Adapter中,通过覆写下面4个方法来实现功能

  package com.hpplay.muiltythreaddemo.viewpagerdemo;

import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.view.ViewGroup;

import java.util.ArrayList;

/**
 * Created by DON on 2016/12/30.
 */
public class ViewPagerAdapter extends FragmentPagerAdapter {

    private ArrayList<Integer> dataBeanArrayList;

    FragmentManager mFm;

    public ViewPagerAdapter(FragmentManager fm, ArrayList<Integer> fragmentArrayList) {
        super(fm);
        this.mFm = fm;
        this.dataBeanArrayList = fragmentArrayList;
    }

    @Override
    public ItemPagerFragment getItem(int position) {
        int realPosition = position % dataBeanArrayList.size();
        ItemPagerFragment itemViewPagerFragment = new ItemPagerFragment();
        itemViewPagerFragment.setData(dataBeanArrayList.get(realPosition));
        return itemViewPagerFragment;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        ItemPagerFragment itemRecyclerViewPagerFragment = (ItemPagerFragment)
                super.instantiateItem(container, position);
        return itemRecyclerViewPagerFragment;
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    @Override
    public int getCount() {
        return dataBeanArrayList.size() <= 1 ? dataBeanArrayList.size() : Integer.MAX_VALUE;
    }


}

上面ItemPagerFragmentViewPager内嵌的Fragment,用于展示具体的图片。
新建类ViewPagerFragment ,实现ViewPager代码

package com.hpplay.muiltythreaddemo.viewpagerdemo;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;

import com.hpplay.muiltythreaddemo.R;

import java.lang.reflect.Field;
import java.util.ArrayList;

/**
 * Created by DON on 2017/7/24.
 */

public class ViewPagerFragment extends Fragment {
    private ViewPager viewPager;
    private ViewPagerAdapter pagerAdapter;
    private ArrayList<Integer> dataBeanArrayList = new ArrayList<>();

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        return View.inflate(getActivity(), R.layout.f_viewpager, null);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        viewPager = (ViewPager) view.findViewById(R.id.viewPager);

        int drawable[] = {R.drawable.im1, R.drawable.im2, R.drawable.im3, R.drawable.im4, R.drawable.im5};
        for (int i = 0; i < drawable.length; i++) {
            dataBeanArrayList.add(drawable[i]);
        }

        pagerAdapter = new ViewPagerAdapter(getActivity().getSupportFragmentManager()
                , dataBeanArrayList);
        viewPager.setAdapter(pagerAdapter);
        viewPager.setPageTransformer(true, new PageTransformer());
        viewPager.setOffscreenPageLimit(2);
        viewPager.setFocusable(true);
        viewPager.setFocusableInTouchMode(true);

        if (dataBeanArrayList.size() > 1) {
            int position = Integer.MAX_VALUE / 2;
            while (position % dataBeanArrayList.size() > 0) {
                ++position;
            }
            viewPager.setCurrentItem(position);//保证ViewPager当前显示的是第一个数据
        }
        pagerAdapter.notifyDataSetChanged();
    }
}

ItemPagerFragment作为ViewPager内嵌的Fragment,实现如下

package com.hpplay.muiltythreaddemo.viewpagerdemo;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.bumptech.glide.Glide;
import com.hpplay.muiltythreaddemo.R;

/**
 * Created by DON on 2016/12/30.
 */
public class ItemPagerFragment extends Fragment {

    private int mDataBean;
    private ImageView imageView;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        return View.inflate(getActivity(), R.layout.item_view_pager, null);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        initView(view);
    }


    public void initView(View view) {
        imageView = (ImageView) view.findViewById(R.id.viewpager_item_iv);
//        imageView.setScaleType(ImageView.ScaleType.MATRIX);

        Glide.with(getActivity())
                .load(mDataBean)
                .centerCrop()
                .crossFade()
                .into(imageView);


        imageView.setFocusable(false);
        imageView.setFocusableInTouchMode(false);


    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
    }

    public void setData(int dataBean) {
        this.mDataBean = dataBean;
    }

}

这个类比较简单,只负责展示图片。但是如果要实现效果图中左右两张图片都要可见的效果,这里的布局文件就要稍作处理,用于显示图片的ImageView不能全屏。
item_view_pager.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/viewpager_item_iv"
        android:layout_width="400dp"
        android:layout_height="180dp"
        android:layout_centerInParent="true" />

</RelativeLayout>

ImageView的父布局是全屏的,这个是没法改变的,如果想要在一个界面中显示ViewPager的三张内容,就先需要在这里把左右两张图片的位置给预留出来,然后通过PageTransformer对左右两张图片做位移,使其能够在界面中显示出来。

二、通过PageTransformer实现特效

package com.hpplay.muiltythreaddemo.viewpagerdemo;

import android.support.v4.view.ViewPager;
import android.view.View;

public class PageTransformer implements ViewPager.PageTransformer {

    /**
     * position会根据view的移动而变化  比如当前有三个view 1,2,3
     * 2在中间的时候,那么view2的position 为 0;
     * 1在左边的时候,那么view1 的position为 -1;
     * 3在右边的时候 , 那么view3的position为1;
     * <p>
     * 所以在view2移动的view3 值得变化范围就是 0---1
     * VIEW2移动的view1 值得变化范围是 0 ---  -1
     * 反之 1---0 , -1 --- 0
     *
     * @param page     移动的View对象
     * @param position 移动位置变化的值
     */
    @Override
    public void transformPage(View page, float position) {
     
        int rorate = (int) (30 + (position - 1) * 30);
        //根据position设置界面上三张图片的旋转角度,实现左右两张图片倾斜的特效
        page.setRotationY(rorate);
        float scale = (float) Math.max(1 - Math.abs(position), 0.74);
        page.setScaleX(scale);
        page.setScaleY(scale);

        //根据position设置界面上三张图片的偏移量,使左右两张图片也能在界面上显示
        page.setTranslationX(-1100 * position);
    }

}

PageTransformer的使用:viewPager.setPageTransformer(true, new PageTransformer());
这里要特别说明,page.setTranslationX(-1100 * position)page.setScaleX(scale)page.setScaleY(scale)page.setRotationY(rorate),这四个方法的值要根据你项目的情况自己去调整大小

三、通过反射修改ViewPager滑动速度

package com.hpplay.muiltythreaddemo.viewpagerdemo;

import android.content.Context;
import android.view.animation.Interpolator;
import android.widget.Scroller;

public class FixedSpeedScroller extends Scroller {
    private int mDuration = 1500;

    public FixedSpeedScroller(Context context) {
        super(context);
    }

    public FixedSpeedScroller(Context context, Interpolator interpolator) {
        super(context, interpolator);
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        // Ignore received duration, use fixed one instead
        super.startScroll(startX, startY, dx, dy, mDuration);
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy) {
        // Ignore received duration, use fixed one instead
        super.startScroll(startX, startY, dx, dy, mDuration);
    }

    public void setmDuration(int time) {
        mDuration = time;
    }

    public int getmDuration() {
        return mDuration;
    }
}

使用:

       try {//调整ViewPager切换滑动速度
            Field field = ViewPager.class.getDeclaredField("mScroller");
            field.setAccessible(true);
            FixedSpeedScroller scroller = new FixedSpeedScroller(viewPager.getContext(),
                    new AccelerateInterpolator());
            field.set(viewPager, scroller);
            scroller.setmDuration(400);
        } catch (Exception e) {
        }

四、控制ViewPager对连续长按遥控器左右键的事件响应

如果不做处理,在用户按着遥控器左右键不松手的时候,ViewPager会快速切换,使界面空白。这一点是在TV APP开发中需要处理的,手机APP开发中不用处理这一点

         //控制ViewPager对连续长按遥控器左右键的事件响应
        viewPager.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (System.currentTimeMillis() - lastKeyTime < 400) {
                    return true;
                }

                if(event.getAction() == KeyEvent.ACTION_UP){
                    lastKeyTime = -1l;
                }else{
                    lastKeyTime = System.currentTimeMillis();
                }
                return false;
            }
        });

lastKeyTime为全局变量,默认-1l,private long lastKeyTime = -1l;

相关文章

网友评论

      本文标题:Android 一个简单的无限循环、带特效的ViewPager

      本文链接:https://www.haomeiwen.com/subject/mghwkxtx.html