自定义组合控件:轮播图

一、项目概述

这里,我们使用自定义组合控件实现一个自动轮播的广告条,也叫轮播图,完整版的效果图如下图所示。其实,这就是我们经常见到的滚动广告,默认情况下每隔N 秒会自动滚动,用手指左右滑动时也会切换到上一张或者下一张。当界面切换时,对应广告图片的标题也会随着改变,并且还有对应图片索引的点也会被选中变为红色。此处,实现的核心控件是ViewPager,它是Android3.0 版本加入的新控件,为了向下兼容,谷歌给我们提供了android-support-v4.jar 包。

自定义控件

二、轮播图UI布局

布局整体采用RelativeLayout,android.support.v4.view.ViewPager,TextView,LinearLayout 配合使用布局文件activity_main.xml 的代码如下文件所示:



    

        

        

            

            
            
        
    

轮播图的代码逻辑实现




    

        
        
        

            

            

        
    

    



public class BannerActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener{

    @Bind(R.id.viewpager)
    public ViewPager mViewPager;
    @Bind(R.id.tvTitle)
    public TextView mTextView;
    @Bind(R.id.llcontainer)
    public LinearLayout mContainer;
    @Bind(R.id.content)
    public LinearLayout mContent;
    @Bind(R.id.recyclerview)
    RecyclerView mRecyclerView;

    private int mPreviousPos;
    private int[] imgs = new int[]{R.mipmap.a, R.mipmap.b, R.mipmap.c, R.mipmap.d, R.mipmap.e};
    private String[] title;
    private ArrayList transformerList = new ArrayList<>();
    private RvAdapter mRvAdapter;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int currentItem = mViewPager.getCurrentItem();
            mViewPager.setCurrentItem(++currentItem);// 跳到下一个页面
            //// 继续发送延时5秒的消息, 形成类似递归的效果, 使广告一直循环切换
            mHandler.sendEmptyMessageDelayed(0, 5000);
        }
    };
    private ViewPagerScroller mScroller;
    private ViewPagerScroller scroller;
    private ActionBar mActionBar;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initView();
        initRecyclerView();
        initListener();
        initTransformer();
        initViewPagerScroll();
    }

    private void initView() {
        setContentView(R.layout.activity_banner);
        ButterKnife.bind(this);
        title = UIUtil.getStringArray(R.array.title);

        SpannableString actionBarTitle = new SpannableString("大图轮播");
        actionBarTitle.setSpan(new ForegroundColorSpan(Color.WHITE), 0, actionBarTitle.length(),
                Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        mActionBar = getSupportActionBar();
        mActionBar.setTitle(actionBarTitle);

        mViewPager.setAdapter(new Adapter());
        int middle = Integer.MAX_VALUE / 2;
        int extra = middle % imgs.length;
        int currentItem = middle - extra;
        mViewPager.setCurrentItem(currentItem);
        mHandler.sendEmptyMessageDelayed(0, 5000);

        for (int i = 0; i < imgs.length; i++) {
            ImageView img = new ImageView(this);
            img.setImageResource(R.drawable.point_selector);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout
                    .LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            if (i != 0) {
                params.leftMargin = 10;
                img.setEnabled(false);
            }
            img.setLayoutParams(params);
            mContainer.addView(img);
        }
        mTextView.setText(title[0]);

       mViewPager.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver
                .OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                BannerActivity.this.onPageSelected(0);
                mViewPager.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }
        });
    }

    private void initRecyclerView() {
        LinearLayoutManager manager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(manager);
        mRvAdapter = new RvAdapter(this, R.layout.list_item, transformerList);
        mRecyclerView.setAdapter(mRvAdapter);
    }

    private void initListener() {
        // 设置滑动监听,根据页面切换时的回调方法,实时获取当前所在页数,并更新下方对应位置的红色的点
        mViewPager.addOnPageChangeListener(this);
        /*new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int
                    positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                int pos = position % imgs.length;
                mTextView.setText(title[pos]);
                mContainer.getChildAt(pos).setEnabled(true);
                mContainer.getChildAt(mPreviousPos).setEnabled(false);
                mPreviousPos = pos;
                colorChange(pos);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        }*/
        //设置ViewPager 的触摸侦听,当用户按下时广告条停止轮播,抬起时又开始轮播
        mViewPager.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        // 清除所有消息和Runnable 对象
                        mHandler.removeCallbacksAndMessages(null);
                        break;
                    case MotionEvent.ACTION_MOVE:
                        break;
                    case MotionEvent.ACTION_UP:
                        // 继续轮播广告
                        mHandler.sendEmptyMessageDelayed(0, 5000);
                        break;
                }
                return false; // 返回false, 让viewpager 原生触摸效果正常运行
            }
        });

        mRvAdapter.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(ViewGroup parent, View view, Object o, int position) {
                String transforemerName = transformerList.get(position);
                try {
                    Class clazz = Class.forName("com.ToxicBakery.viewpager.transforms." +
                            transforemerName);
                    ABaseTransformer transformer = (ABaseTransformer) clazz.newInstance();
                    mViewPager.setPageTransformer(true, transformer);
                    if (transforemerName.equals("StackTransformer")) {
                        scroller.setScrollDuration(1200);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public boolean onItemLongClick(ViewGroup parent, View view, Object o, int position) {
                return false;
            }
        });
    }

    /**
     * 设置ViewPager的滑动速度
     */
    private void initViewPagerScroll() {
        Field mScroller = null;
        try {
            mScroller = ViewPager.class.getDeclaredField("mScroller");
            mScroller.setAccessible(true);
            scroller = new ViewPagerScroller(mViewPager.getContext());
            mScroller.set(mViewPager, scroller);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private void initTransformer() {
        //各种翻页效果
        transformerList.add(DefaultTransformer.class.getSimpleName());
        transformerList.add(AccordionTransformer.class.getSimpleName());
        transformerList.add(BackgroundToForegroundTransformer.class.getSimpleName());
        transformerList.add(CubeInTransformer.class.getSimpleName());
        transformerList.add(CubeOutTransformer.class.getSimpleName());
        transformerList.add(DepthPageTransformer.class.getSimpleName());
        transformerList.add(FlipHorizontalTransformer.class.getSimpleName());
        transformerList.add(FlipVerticalTransformer.class.getSimpleName());
        transformerList.add(ForegroundToBackgroundTransformer.class.getSimpleName());
        transformerList.add(RotateDownTransformer.class.getSimpleName());
        transformerList.add(RotateUpTransformer.class.getSimpleName());
        transformerList.add(StackTransformer.class.getSimpleName());
        transformerList.add(ZoomInTransformer.class.getSimpleName());
        transformerList.add(ZoomOutTranformer.class.getSimpleName());

        mRvAdapter.notifyDataSetChanged();
    }

    private void colorChange(int pos) {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgs[pos]);
        Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
            @Override
            public void onGenerated(Palette palette) {
                Palette.Swatch vibrant = palette.getVibrantSwatch();
                mContent.setBackgroundColor(toARGB(vibrant.getRgb()));
                mTextView.setTextColor(vibrant.getBodyTextColor());
                mActionBar.setBackgroundDrawable(new ColorDrawable(vibrant.getRgb()));

                if (Build.VERSION.SDK_INT >=21){
                    Window window = getWindow();
                    window.setStatusBarColor(colorBurn(vibrant.getRgb()));
                    //window.setNavigationBarColor(Color.RED);
                }
            }
        });
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        int pos = position % imgs.length;
        mTextView.setText(title[pos]);
        mContainer.getChildAt(pos).setEnabled(true);
        if (pos != mPreviousPos){
            mContainer.getChildAt(mPreviousPos).setEnabled(false);
        }
        mPreviousPos = pos;
        colorChange(pos);
    }

    /**
     * 颜色添加透明度
     * @param rgb
     * @return
     */
    protected  static  int toARGB(int rgb){
        int red = rgb >> 16 & 0xFF;
        int green = rgb >> 8 & 0xFF;
        int blue = rgb & 0xFF;
        return Color.argb(180 , red , green , blue );
    }

    /**
     * 颜色加深处理
     * @param RGBValues
     * @return
     */
    private int colorBurn(int RGBValues) {
        int alpha = RGBValues >> 24;
        int red = RGBValues >> 16 & 0xFF;
        int green = RGBValues >> 8 & 0xFF;
        int blue = RGBValues & 0xFF;
        red = (int) Math.floor(red * (1 - 0.1));
        green = (int) Math.floor(green * (1 - 0.1));
        blue = (int) Math.floor(blue * (1 - 0.1));
        return Color.rgb(red, green, blue);
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

    private class Adapter extends PagerAdapter {

        @Override
        public int getCount() {
            if (imgs.length != 0) {
                return Integer.MAX_VALUE;
            }
            return 0;
        }

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            int pos = position % imgs.length;
            ImageView img = new ImageView(BannerActivity.this);
            img.setBackgroundResource(imgs[pos]);
            container.addView(img);
            return img;
        }

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

    private class RvAdapter extends CommonAdapter {

        public RvAdapter(Context context, int layoutId, List datas) {
            super(context, layoutId, datas);
        }

        @Override
        public void convert(ViewHolder holder, String s) {
            holder.setText(R.id.tv_item, s);
        }
    }
}

知识点总结

1.ViewPager 的使用方式与ListView 类似,都是通过适配器来设置要显示的内容,ViewPager 使用PagerAdapter,ListView 使用BaseAdapter。PagerAdapter 中的各个方法使用见MainActivity.java 中90 到122 行。

2.动态添加图片描述和切换的点,点的个数是随着广告条设置的图片张数动态改变的,因此在MainActivity.java 中59 行,创建ViewPager 的图片内容时,同时创建点并添加到我们存放点的水平的LinearLayout 中(MainActivity.java 第68 行)。

3.广告条伪无限循环实现,viewpager 会最多预加载3 张图片,即当前界面图片、前一张和后一张的图片,当索引为0 时,不加载左边的图片,不能向左滑动,当索引为getcount -1,不加载右边的图片,不能向右滑动,我们设置了长度为Integer.MAX_VALUE,在根据position 获取值时,通过取模运算,保证数据集合脚标不越界。并且在初始时,通过mViewPager.setCurrentItem(mImageIds.length * 1000)方法,让ViewPager 显示到一个较大索引值的位置,这样就实现了伪无限循环。

4 . 代码:https://github.com/JackChen1999/Banner

开源项目

Android-ConvenientBanner

DecentBanner

AndroidImageSlider

https://github.com/JackChen1999/Banner

你可能感兴趣的:(自定义组合控件:轮播图)