真正的画廊,左右条目可点击居中, 左右条目可滑动

利用Viewpager实现真正的Gallery, 左右条目可点击居中, 左右条目可滑动,也就是可以获得焦点

前言: 最近公司做一个想Gallery一样的效果,于是想在网上找个现成的,但是怎么找也没找到,就是找到一个鸿洋大神的巧用ViewPager 打造不一样的广告轮播切换效果的,但是左右条目不可点击,又不可以滑动,所以就做了个这个控件,本控件也是利用ViewPgaer做出来的

首先看一下效果:

这里写图片描述
从图上可以看出, 两边的item可以被点击居中, 可以被滑动,也就是可以获得焦点

接下来讲一下原理

设置PageTransformer

PageTransformer大家估计都相当熟悉吧,下面是PageTransformer的代码

public void transformPage(View page, float position) {

    if (position < -1) {
        position = -1;
    } else if (position > 1) {
        position = 1;
    }

    float tempScale = position < 0 ? 1 + position : 1 - position;

    float slope = (MAX_SCALE - MIN_SCALE) / 1;

    float scaleValue = MIN_SCALE + tempScale * slope;
    page.setScaleX(scaleValue);
    page.setScaleY(scaleValue);

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
        page.getParent().requestLayout();
    }
}

这个的作用就是让Viewpager展示多个条目,看下面的图片, 红色的才是ViewPager的大小,所以此PageTransformer是为了在Viewpager外面展示图片

这里写图片描述

大家都知道PageTransformer没有真正的改变viewpager的状态,但是为什么本demo中两侧的图片可以点击还可以滑动呢,让我慢慢跟你道来

其实很简单,就是在viewpage的父控件中拦截dispatchTouchEvent的方法来控制ViewPgaer的滑动和相应点击事件的(不懂dispatchTouchEvent即事件分发的, 问问度娘就可以了)

先看一下自定义ViewPager
public class GalleryViewPager extends ViewPager {
//默认距离
private final static float DISTANCE = 10;
private float downX;
private float downY;

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

public GalleryViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if(ev.getAction() == MotionEvent.ACTION_DOWN){
        downX = ev.getX();
        downY = ev.getY();
    }else if (ev.getAction() == MotionEvent.ACTION_UP) {

        float upX = ev.getX();
        float upY = ev.getY();

        if(Math.abs(upX - downX) > DISTANCE || Math.abs(upY - downY) > DISTANCE){
            return super.dispatchTouchEvent(ev);
        }

        View view = viewOfClickOnScreen(ev);
        if (view != null) {
            int index = (Integer) view.getTag();
            if (getCurrentItem() != index) {
                setCurrentItem(index);
            }
        }
    }
    return super.dispatchTouchEvent(ev);
}


private View viewOfClickOnScreen(MotionEvent ev) {
    int childCount = getChildCount();
    int currentIndex = getCurrentItem();
    int[] location = new int[2];
    for (int i = 0; i < childCount; i++) {
        View v = getChildAt(i);
        int position = (Integer) v.getTag();
        v.getLocationOnScreen(location);
        int minX = location[0];
        int minY = location[1];

        int maxX = location[0] + v.getWidth();
        int maxY = location[1] + v.getHeight();

        if(position < currentIndex){
            maxX -= v.getWidth() * (1 - ScalePageTransformer.MIN_SCALE) * 0.5 + v.getWidth() * (Math.abs(1 - ScalePageTransformer.MAX_SCALE)) * 0.5;
            minX -= v.getWidth() * (1 - ScalePageTransformer.MIN_SCALE) * 0.5 + v.getWidth() * (Math.abs(1 - ScalePageTransformer.MAX_SCALE)) * 0.5;
        }else if(position == currentIndex){
            minX += v.getWidth() * (Math.abs(1 - ScalePageTransformer.MAX_SCALE));
        }else if(position > currentIndex){
            maxX -= v.getWidth() * (Math.abs(1 - ScalePageTransformer.MAX_SCALE)) * 0.5;
            minX -= v.getWidth() * (Math.abs(1 - ScalePageTransformer.MAX_SCALE)) * 0.5;
        }
        float x = ev.getRawX();
        float y = ev.getRawY();

        if ((x > minX && x < maxX) && (y > minY && y < maxY)) {
            return v;
        }
    }
    return null;
}
}

等会让VIewPgaer的父控件的dispatchTouchEvent实现此ViewPager的dispatchTouchEvent就可以了 比如在mainactivity中找到父控件, 根据父控件的dispatchTouchEvent来控制此ViewPgaer的变化

    findViewById(R.id.root).setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return mViewPager.dispatchTouchEvent(event);
        }
    });

控制两边图片的点击事件只响应居中图片, 不响应点击事件

在viewpageradapter中设置如下代码, 中间的图片永远是mViewPager.getCurrentItem(),只有中间的图片可以响应点击事件

   imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("wwwwwwwwss", mViewPager.getCurrentItem()+ "------" + position);
                if ((mViewPager.getCurrentItem() ) == position) {
                    Toast.makeText(mContext, "点击的位置是:::"+position, Toast.LENGTH_SHORT).show();
                }

            }
        });

使用方式

添加依赖

1.在根目录的build.gradle中添加

allprojects {
repositories {
    jcenter()
    maven { url 'https://jitpack.io' }// 添加jitpack.依赖
}

2.在app的build.gradle中添加

    compile 'com.github.niezhiyang:NGallery:v1.0.1'

在使用的xml中,用一个父控件包裹住GalleryViewPager,目的是为了控制父控件的滑动,和点击,来设置Viewpager的状态

<RelativeLayout
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    >
    <!--是否限制子View在其范围内,我们将其值设置为false后那么当子控件的高度高于父控件时也会完全显示,而不会被压缩-->
    <com.nie.ngallerylibrary.GalleryViewPager
        android:id="@+id/viewpager"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
        android:clipChildren="false"
        android:overScrollMode="never"/>
</RelativeLayout>

代码中设置

    mViewPager = (GalleryViewPager) findViewById(R.id.viewpager);//找到这个控件
    mViewPager.setPageTransformer(true, new ScalePageTransformer());//设置PageTransformer,本库只有一个ScalePageTransformer,如果这个ScalePageTransformer满足不了您的需求,您可以自己写一个PageTransformer
    findViewById(R.id.root).setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return mViewPager.dispatchTouchEvent(event);
        }
    });//找到这个父控件设置他的listener

    mPagerAdapter = new SimpleAdapter(this);//初始化adapter
    mViewPager.setAdapter(mPagerAdapter);//设置adapter

adapter要继承MyPageradapter;例如

public class SimpleAdapter extends MyPageradapter {

    private final List<Integer> mList;
    private final Context mContext;

    public SimpleAdapter(Context context) {
        mList = new ArrayList<>();
        mContext = context;
    }

    public void addAll(List<Integer> list) {
        mList.addAll(list);
        notifyDataSetChanged();
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup container) {
        ImageView imageView = null;
        if (convertView == null) {
            imageView = new ImageView(mContext);
        } else {
            imageView = (ImageView) convertView;
        }
        imageView.setTag(position);
        imageView.setImageResource(mList.get(position));
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if ((mViewPager.getCurrentItem() ) == position) {
                    Toast.makeText(mContext, "点击的位置是:::"+position, Toast.LENGTH_SHORT).show();
                }

            }
        });

        return imageView;
    }

    @Override
    public int getCount() {
        return mList.size();
    }
}

这只不过是简单的添加imageview,你也可以添加fragment做出绚丽的效果,还可以跟任意的viewpgaerindicator使用了,是不是想想就高兴了

具体实现请看源码:NGallery

apk位置:demo.apk

欢迎start

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值