利用ViewPager实现画廊Gallery效果

1、 需求确认

最近做的一个小学的定制项目,谈需求的时候客户提到一个界面的效果。

客户:这个界面我们需要显示一张XX图片,但是它可以左右滑,为了知道它可以滑,需要在两边露一点比较小的图出来。

UI : 设计的原型图:
这里写图片描述

这是客户提出的需求,我们作为程序员需要转换为自己的理解:

这个界面我们需要使用列表进行展示,RecycleView或者Viewpager
关键是,左右需要露一点出来,如果用RecycleView的话需要让item占满全屏,左右露一点不太好实现,如果不让item占满全屏,就会出现滑动到两个item中间的情况。
所以应该是使用Viewpager,但是Viewpager怎么露出两侧的图呢?(我在网上游弋的时候,发现这种效果的名字叫做画廊,android有个控件Gallery就是用来实现这个效果的,但是现在不建议使用了,好贴切、好立体的名字。/(ㄒoㄒ)/~~原谅自己的无知,瞬间阿Q精神上身—-又找到一个可以装B的点了,O(∩_∩)O哈哈哈~)
so,我就稍稍必应了一下(本来想说百度了一下的,但是渣渣的百度搜索,我还是喜欢用必应,尤其是必应的bg图。O(∩_∩)O哈哈哈~),用viewpager是可以做到的,只是需要利用它的两个属性。


2、利用viewpager实现画廊效果

1 、viewpager的继承关系

这里写图片描述


2 、使用ViewGroup的setClipChildren(boolean clipChildren)方法

当然也可以在XML文件里面设置,属性为clipChildren

这里写图片描述

在代码中使用,就是setClipChildren()
这里写图片描述

这个方法或者属性的作用就是viewgroup的子view是否在它应有的边界内绘制。默认为true,在其边界内绘制。

so,我们就解决了核心的一点,怎么在两边露出图片的问题。接下来就是让切换的效果好看一点,切换的时候,把两边的图片变小一点,把中间的图片变大一点。


3 、使用viewpager的setPageTransformer(…)方法实现vp页面切换效果

这里写图片描述

这个方法的作用是,设置一个ViewPager.PageTransformer,每当更改滚动位置时,将为每个附加的页面调用它。意思就是VP切换界面的时候会调用这个ViewPager.PageTransformer以实现页面切换的动画效果。

其实许多ViewPager切换效果都是通过创建一个类实现ViewPager.PageTransformer然后重写transformPage方法来实现各种切换效果,放大缩小、旋转、倒影等等


3、实战代码

1 、首先是父级布局

这里写图片描述

代码

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/class_honor"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    android:gravity="center"
    tools:context="com.cnbs.eleclasscard.activity.growing.ClassHonorFragment">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="-30dp"
        android:layout_marginBottom="50dp"
        android:src="@mipmap/bg_growing_class_honor" />

    <android.support.v4.view.ViewPager
        android:id="@+id/class_honor_vp"
        android:layout_width="800dp"
        android:layout_height="600dp"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="90dp"
        android:clipChildren="false"/>


</RelativeLayout>

特别说明:这个应用是在学校特定的设备上开发的,所以我根本没有考虑适配其他的设备O(∩_∩)O~


2 、viewpager需要显示的内容

就一张图片,所以在孩子fragment的布局文件

这里写图片描述

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp"
    tools:context="com.cnbs.eleclasscard.activity.growing.ClassHonorItemFragment">

  <ImageView
      android:id="@+id/class_honor_img"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:scaleType="fitXY"
      android:src="@mipmap/img_loading43"/>

</FrameLayout>

3 、实现画廊效果

1. viewpager和其父级布局都需要禁止让子view在其限制内绘制

private void initView() {
        classHonorVp.setClipChildren(false); //VP的内容可以不在限制内绘制
        classHonor.setClipChildren(false);  //VP可以不在限制内绘制
        adapter = new ClassHonorPageAdapter(getChildFragmentManager(), mContext, data); 
        classHonorVp.setAdapter(adapter);
        //实现画廊效果
        classHonorVp.setPageTransformer(true, new ZoomOutPageTransformer());   //实现需要的页面转换效果
        classHonorVp.setOffscreenPageLimit(2); //缓存页面数
        classHonorVp.setPageMargin(100); //每页的间隔
        //触摸事件反馈给viewpager
        classHonor.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return classHonorVp.dispatchTouchEvent(event);
            }
        });
    }

补上,ClassHonorPageAdapter的代码

public class ClassHonorPageAdapter extends FragmentStatePagerAdapter {
    private Activity mContext;
    private List<HonorBean> mData;

    public ClassHonorPageAdapter(FragmentManager fm, Activity context, List<HonorBean> data) {
        super(fm);
        this.mContext = context;
        this.mData = data;
    }

    public void refresh(List<HonorBean> data){
        this.mData = data;
        notifyDataSetChanged();
    }

    @Override
    public Fragment getItem(int position) {
        return ClassHonorItemFragment.newInstance(mContext,mData.get(position));
    }

    @Override
    public int getCount() {
        return mData==null?0:mData.size();
    }

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

}

2. 创建一个类实现ViewPager.PageTransformer,实现页面转换效果

 //实现当前页面放大效果
    class ZoomOutPageTransformer implements ViewPager.PageTransformer {
        private static final float MAX_SCALE = 1.0f;
        private static final float MIN_SCALE = 0.7f;

        @Override
        public void transformPage(View view, float position) {
            if (position < -1) {
                view.setScaleX(MIN_SCALE);
                view.setScaleY(MIN_SCALE);
            } else if (position <= 1) {
                float scaleFactor = MIN_SCALE + (1 - Math.abs(position)) * (MAX_SCALE - MIN_SCALE);
                view.setScaleX(scaleFactor);
                if (position > 0) {
                    view.setTranslationX(-scaleFactor * 2);
                } else if (position < 0) {
                    view.setTranslationX(scaleFactor * 2);
                }
                view.setScaleY(scaleFactor);
            } else {
                view.setScaleX(MIN_SCALE);
                view.setScaleY(MIN_SCALE);
            }

        }
    }

3. 补充一个,让左右都有图

 adapter.refresh(list);
 classHonorVp.setCurrentItem(1);

如果没有这个需求就不用,另外有时显示的效果没有处理,我们可以这样写:

classHonorVp.setCurrentItem(1);
classHonorVp.setCurrentItem(0);
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
实现自定义画廊效果,可以通过继承ViewPager类,重写其onInterceptTouchEvent()和onTouchEvent()方法,并在onDraw()方法中绘制自定义效果。 以下是一个简单的实现步骤: 1. 继承ViewPager类,重写onInterceptTouchEvent()和onTouchEvent()方法,用于捕捉和处理触摸事件。 ```java public class GalleryViewPager extends ViewPager { private float mLastMotionX; private int mTouchSlop; public GalleryViewPager(Context context) { super(context); init(); } public GalleryViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { ViewConfiguration config = ViewConfiguration.get(getContext()); mTouchSlop = config.getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction(); if ((action == MotionEvent.ACTION_MOVE) && (Math.abs(mLastMotionX - ev.getX()) > mTouchSlop)) { return true; } mLastMotionX = ev.getX(); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { return super.onTouchEvent(ev); } } ``` 2. 在onDraw()方法中绘制自定义效果。例如,可以绘制一个圆形的选中框,并将当前选中的页面放大。 ```java public class GalleryViewPager extends ViewPager { // ... private Paint mPaint; private RectF mRectF; private float mRadius; // 当前选中的页面索引 private int mCurrentPageIndex = 0; public GalleryViewPager(Context context) { super(context); init(); } public GalleryViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { // ... mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(4); mPaint.setColor(Color.WHITE); mRadius = 100; mRectF = new RectF(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (getChildCount() <= 0) { return; } // 绘制圆形选中框 float cx = getWidth() / 2f; float cy = getHeight() / 2f; float x = cx - mRadius; float y = cy - mRadius; mRectF.set(x, y, x + 2 * mRadius, y + 2 * mRadius); canvas.drawOval(mRectF, mPaint); // 放大当前选中的页面 View currentPage = getChildAt(mCurrentPageIndex); float currentScale = 1.2f; float scale = (currentPage.getWidth() * currentScale) / currentPage.getWidth(); currentPage.setScaleX(scale); currentPage.setScaleY(scale); } // ... } ``` 3. 在onPageSelected()方法中更新当前选中的页面索引,并调用invalidate()方法强制重绘。 ```java public class GalleryViewPager extends ViewPager { // ... @Override public void onPageSelected(int position) { mCurrentPageIndex = position; invalidate(); super.onPageSelected(position); } // ... } ``` 最后,使用自定义的GalleryViewPager代替原来的ViewPager即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值