android 画廊效果(中间大两边小)的无限轮播banner

android 画廊效果(中间大两边小)的无限轮播banner

ps: 项目要求做一个中间大两边小的轮播图,百度了一圈有了些灵感,分享一下心得,国际惯例先上效果图
banner.gif

废话不多说,直接上关键代码:

/**
 * Created by tf on 2018/12/21.
 */

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.widget.Scroller;
import android.widget.TextView;

import com.hexin.cardservice.R;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class LoopViewPager extends ViewPager {

    OnPageChangeListener mOuterPageChangeListener;
    private LoopPagerAdapterWrapper mAdapter;

    private MyHandler mHandler;
    private final static int HANDLE_LOOP_MSG = 101;
    private AtomicBoolean isAutoLoop = new AtomicBoolean();

    public void setTxtPoints(List<TextView> txtPoints) {
        this.txtPoints = txtPoints;
    }

    private List<TextView> txtPoints;

    public void changePoints(int pos) {
        if (txtPoints != null) {
            for (int i = 0; i < txtPoints.size(); i++) {
                if (pos == i) {
                    txtPoints.get(i).setBackgroundResource(R.mipmap.home_yuan_sel);
                } else {
                    txtPoints.get(i).setBackgroundResource(R.mipmap.home_yuan);
                }
            }
        }
    }

    @Override
    public void setAdapter(PagerAdapter adapter) {
        mAdapter = new LoopPagerAdapterWrapper(adapter);
        super.setAdapter(mAdapter);
        isAutoLoop.set(false);
        setCurrentItem(0, false);
    }

    @Override
    public PagerAdapter getAdapter() {
        return mAdapter != null ? mAdapter.getRealAdapter() : mAdapter;
    }

    /**
     * 获取当前真实的item
     *
     * @return
     */
    public int getRealItem() {
        return mAdapter != null ? mAdapter.toRealPosition(super.getCurrentItem()) : 0;
    }

    public void setCurrentItem(int item, boolean smoothScroll) {
        int realItem = mAdapter.toInnerPosition(item);
        super.setCurrentItem(realItem, smoothScroll);
    }


    @Override
    public void setOnPageChangeListener(OnPageChangeListener listener) {
        mOuterPageChangeListener = listener;
    }

    public LoopViewPager(Context context) {
        super(context);
        init();
    }

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

    private void init() {
        super.setOnPageChangeListener(onPageChangeListener);
        try {
            Field scrollerField = ViewPager.class.getDeclaredField("mScroller");
            scrollerField.setAccessible(true);
            Field interpolator = ViewPager.class.getDeclaredField("sInterpolator");
            interpolator.setAccessible(true);

            Scroller scroller = new Scroller(getContext(), (Interpolator) interpolator.get(null)) {
                @Override
                public void startScroll(int startX, int startY, int dx, int dy, int duration) {
                    //控制滑动速度
                    super.startScroll(startX, startY, dx, dy, (int) (1300 * (double) Math.abs(dx) / getWidth(getContext())));
                }
            };
            scrollerField.set(this, scroller);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void autoLoop(boolean isAuto) {
        if (mHandler == null) {
            mHandler = new MyHandler(getContext());
        }
        if (isAuto) {
            mHandler.sendEmptyMessageDelayed(HANDLE_LOOP_MSG, 3000);
        } else {
            mHandler.removeCallbacksAndMessages(null);
        }
        isAutoLoop.set(isAuto);
    }

    private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() {
        private float mPreviousOffset = -1;
        private float mPreviousPosition = -1;

        @Override
        public void onPageSelected(int position) {

            int realPosition = mAdapter.toRealPosition(position);
            changePoints(realPosition);
            if (mPreviousPosition != realPosition) {
                mPreviousPosition = realPosition;
                if (mOuterPageChangeListener != null) {
                    mOuterPageChangeListener.onPageSelected(realPosition);
                }
            }
        }

        @Override
        public void onPageScrolled(int position, float positionOffset,
                                   int positionOffsetPixels) {
            int realPosition = position;
            if (mAdapter != null) {
                realPosition = mAdapter.toRealPosition(position);

                if (positionOffset == 0
                        && mPreviousOffset == 0
                        && (position == 0 || position == mAdapter.getCount() - 1)) {
                    setCurrentItem(realPosition, false);
                }
            }

            mPreviousOffset = positionOffset;
            if (mOuterPageChangeListener != null) {
                if (realPosition != mAdapter.getRealCount() - 1) {
                    mOuterPageChangeListener.onPageScrolled(realPosition,
                            positionOffset, positionOffsetPixels);
                } else {
                    if (positionOffset > .5) {
                        mOuterPageChangeListener.onPageScrolled(0, 0, 0);
                    } else {
                        mOuterPageChangeListener.onPageScrolled(realPosition,
                                0, 0);
                    }
                }
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            switch (state) {
                case SCROLL_STATE_DRAGGING:
                    if (isAutoLoop.get()) {
                        mHandler.removeCallbacksAndMessages(null);
                    }
                    break;
                case SCROLL_STATE_IDLE:
                    if (isAutoLoop.get()) {
                        mHandler.sendEmptyMessageDelayed(HANDLE_LOOP_MSG, 3000);
                    }
                    break;
                case SCROLL_STATE_SETTLING:
                    break;
            }
            if (mOuterPageChangeListener != null) {
                mOuterPageChangeListener.onPageScrollStateChanged(state);
            }
        }
    };

//    @Override
//    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//
//        int height = 0;
//        for (int i = 0; i < getChildCount(); i++) {
//            View child = getChildAt(i);
//            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
//            int h = child.getMeasuredHeight();
//            if (h > height)
//                height = h;
//        }
//        int width = 0;
//        for (int i = 0; i < getChildCount(); i++) {
//            View child = getChildAt(i);
//            child.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightMeasureSpec);
//            int h = child.getMeasuredWidth();
//            if (h > width)
//                width = h;
//        }
//
//        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
//        widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
//
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//    }

    private class MyHandler extends Handler {

        WeakReference<Context> mWeakReference;

        public MyHandler(Context context) {
            mWeakReference = new WeakReference<>(context);
        }

        @Override
        public void handleMessage(Message msg) {
            final Context context = mWeakReference.get();
            if (context == null) {
                return;
            }
            switch (msg.what) {
                case HANDLE_LOOP_MSG:
                    int curItem = getCurrentItem();
                    setCurrentItem(++curItem);
                    changePoints(curItem % txtPoints.size() );
                    break;
            }
        }
    }


    public int getWidth(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }
}

  • LoopPagerAdapterWrapper类
  package com.hexin.cardservice.ui.customView;

/**
 * Created by 15061 on 2018/12/21.
 */

import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

public class LoopPagerAdapterWrapper extends PagerAdapter {

    private PagerAdapter mAdapter;

    LoopPagerAdapterWrapper(PagerAdapter adapter) {
        this.mAdapter = adapter;
    }

    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
    }

    public int toInnerPosition(int realPosition) {
        return realPosition + getCount() / 2  - getCount() % getRealCount();
    }

    int toRealPosition(int position) {
        return position % getRealCount();
    }

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

    public int getRealCount() {
        return mAdapter.getCount();
    }

    public PagerAdapter getRealAdapter() {
        return mAdapter;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        int realPosition = position % getRealCount();
        return mAdapter.instantiateItem(container, realPosition);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        int realPosition = position % getRealCount();
        mAdapter.destroyItem(container, realPosition, object);
    }

    @Override
    public void finishUpdate(ViewGroup container) {
        mAdapter.finishUpdate(container);
    }

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

    @Override
    public void restoreState(Parcelable bundle, ClassLoader classLoader) {
        mAdapter.restoreState(bundle, classLoader);
    }

    @Override
    public Parcelable saveState() {
        return mAdapter.saveState();
    }

    @Override
    public void startUpdate(ViewGroup container) {
        mAdapter.startUpdate(container);
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        mAdapter.setPrimaryItem(container, position, object);
    }
}

配置文件代码

<RelativeLayout
                android:id="@+id/relativelayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="15dp">

                <.LoopViewPager
                    android:id="@+id/myviewpager"
                    android:layout_width="match_parent"
                    android:layout_height="125dp" />
                <!-- 存放圆点 -->
                <LinearLayout
                    android:id="@+id/layout_dots"
                    android:layout_width="wrap_content"
                    android:layout_height="30dp"
                    android:layout_alignParentBottom="true"
                    android:layout_centerHorizontal="true"
                    android:gravity="center"
                    android:orientation="horizontal"/>
            </RelativeLayout>

MainActivity 应用

初始化ViewPager

private void initViewPager() {

        mViewpager = view.findViewById(R.id.myviewpager);
        //图片圆角处理
        for (int i = 0; i < mBannerArr.length; i++) {
            ImageView view1 = new ImageView(getContext());
            RoundedBitmapDrawable roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(getResources(), BitmapFactory.decodeResource(getResources(), mBannerArr[i]));
            //view1.setImageResource(R.mipmap.pic);
            roundedBitmapDrawable.setCornerRadius(30);
            view1.setImageDrawable(roundedBitmapDrawable);
            mImageList.add(view1);
        }

        mViewpager.setClipChildren(false);
        DisplayMetrics dm = getResources().getDisplayMetrics();
        mViewpager.setPageMargin(-dm.widthPixels / 13);//设置viewpage之间的间距

        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mViewpager.getLayoutParams();
        //高度根据图片进行适配(这里图片为750 *300)
        params.height = (int) (getResources().getDisplayMetrics().widthPixels * 330 / 750.0);
        params.width = getResources().getDisplayMetrics().widthPixels;
        mViewpager.setLayoutParams(params);
        mViewpager.setAdapter(new MyAdapter());
        mViewpager.setPageTransformer(true, new ViewPager.PageTransformer() {
            float scale = 0.85f;

            @Override
            public void transformPage(View page, float position) {
                if (position >= 0 && position <= 1) {
                    page.setScaleY(scale + (1 - scale) * (1 - position));
                } else if (position > -1 && position < 0) {
                    page.setScaleY(1 + (1 - scale) * position);
                } else {
                    page.setScaleY(scale);
                }
            }
        });
        mViewpager.autoLoop(true);
}

初始化指示器小圆点

/**
     * 初始化小圆点
     */
    private void initCircle() {
        mLayoutPoints = view.findViewById(R.id.layout_dots);
        mTxtPoints = new ArrayList<>();
        int d = DensityUtils.dp2px(mContext, 6);
        int m = 10;
        for (int i = 0; i < mImageList.size(); i++) {
            TextView txt = new TextView(getContext());
            if (i == 0) {
                txt.setBackgroundResource(R.mipmap.home_yuan_sel);
            } else {
                txt.setBackgroundResource(R.mipmap.home_yuan);
            }
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(d, d);
            params.setMargins(m, m, m, m);
            txt.setLayoutParams(params);
            mTxtPoints.add(txt);
            mLayoutPoints.addView(txt);
        }
        mViewpager.setTxtPoints(mTxtPoints);
    }

viewpager自定义适配器:

class MyAdapter extends PagerAdapter {

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

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

        @Override
        public Object instantiateItem(ViewGroup container, final int position) {
            ImageView view = mImageList.get(position);
            ViewParent viewParent = view.getParent();
            if (viewParent == null) {
                container.addView(view);
            }

            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    log.d(TAG, "点击了第" + postion + "张图");
                }
            });
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }
    }

PS:这些就是轮播效果图了,希望对读者有帮助。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352