1. 程式人生 > >自定義組合控制元件:Banner、輪播圖、廣告欄控制元件

自定義組合控制元件:Banner、輪播圖、廣告欄控制元件

1. 專案概述

這裡,我們使用自定義組合控制元件實現一個自動輪播的廣告條,也叫輪播圖,完整版的效果圖如下圖所示。其實,這就是我們經常見到的滾動廣告,預設情況下每隔N 秒會自動滾動,用手指左右滑動時也會切換到上一張或者下一張。當介面切換時,對應廣告圖片的標題也會隨著改變,並且還有對應圖片索引的點也會被選中變為紅色。此處,實現的核心控制元件是ViewPager,它是Android3.0 版本加入的新控制元件,為了向下相容,谷歌給我們提供了android-support-v4.jar 包。

這裡寫圖片描述

2. 輪播圖UI佈局

佈局整體採用RelativeLayout,android.support.v4.view.ViewPager,TextView,LinearLayout 配合使用佈局檔案activity_main.xml 的程式碼如下檔案所示:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v4.view.ViewPager
android:id="@+id/vp_pager" android:layout_width="match_parent" android:layout_height="160dp"/>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:background
="#a000" android:orientation="vertical" android:padding="5dp">
<TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新聞標題" android:textColor="#fff" android:textSize="16sp"/> <LinearLayout android:id="@+id/ll_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="horizontal"> </LinearLayout> </LinearLayout> </FrameLayout> </RelativeLayout>

3. 輪播圖的程式碼邏輯實現

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

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v4.view.ViewPager
            android:id="@id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="180dp"/>
        <!--android:background="#a000"-->
        <LinearLayout
            android:id="@id/content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:orientation="vertical"
            android:padding="5dp">

            <TextView
                android:id="@id/tvTitle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textColor="#fff"
                android:textSize="16sp"/>

            <LinearLayout
                android:id="@id/llcontainer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp"
                android:gravity="center_horizontal"
                android:orientation="horizontal"/>

        </LinearLayout>
    </FrameLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>
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<String> transformerList = new ArrayList<>();
    private RvAdapter mRvAdapter;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int currentItem = mViewPager.getCurrentItem();
            mViewPager.setCurrentItem(++currentItem);
            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) {

            }
        }*/

        mViewPager.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mHandler.removeCallbacksAndMessages(null);
                        break;
                    case MotionEvent.ACTION_MOVE:
                        break;
                    case MotionEvent.ACTION_UP:
                        mHandler.sendEmptyMessageDelayed(0, 5000);
                        break;
                }
                return false;
            }
        });

        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<String> {

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

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

4. 把Banner封裝成一個模組

public class RollViewPager extends ViewPager implements ViewPager.OnPageChangeListener {

    private List<String> mImageLists;
    private List<String> mTitleLists;
    private List<View>   mDotLists;
    public  Context      mContext;
    private TextView     mTopNewsTitle;
    private Task         mTask;
    private boolean hasAdapter   = false;
    private int     oldPosition  = 0;
    private int     mCurrentItem = 0;
    private int  downX;
    private int  downY;
    private long downTimeMillis;

    // 是否滑動
    private boolean isMove = false;

    public RollViewPager(Context context, List<View> mDotLists) {
        super(context);
        this.mDotLists = mDotLists;
        this.mContext = context;
        mTask = new Task();

        // 設定viewpager 的觸控事件
        RollViewPager.this.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                // 當手指觸控到螢幕的時候。viewpage 停止跳動
                // 當手指離開螢幕的時候。viewpage 繼續跳動

                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    // 獲取到down 的時間

                    downTimeMillis = System.currentTimeMillis();

                    // 停止跳動
                    // 刪除訊息
                    handler.removeCallbacksAndMessages(null);

                    // 刪除任務
                    //handler.removeCallbacks(mTask);
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    // 獲取的是當前時間
                    long currentTimeMillis = System.currentTimeMillis();
                    if (currentTimeMillis - downTimeMillis < 500) {
                        // Toast.makeText(mContext, "我被點選了", 0).show();
                        if (mViewPageOnTouchListener != null) {
                            mViewPageOnTouchListener.onViewPageClickListener();
                        }
                    }
                    // 繼續跳動
                    start();
                } else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
                    System.out.println("MotionEvent.ACTION_CANCEL");
                    start();
                }

                return false;
            }
        });
    }

    public void start() {
        if (!hasAdapter) {
            hasAdapter = true;
            RollViewPagerAdapter adapter = new RollViewPagerAdapter();
            RollViewPager.this.setAdapter(adapter);
            RollViewPager.this.setOnPageChangeListener(this);
        }
        handler.postDelayed(mTask, 2000);
    }

    public void stop() {
        handler.removeCallbacksAndMessages(null);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        super.onPageScrolled(position, positionOffset, positionOffsetPixels);
    }

    @Override
    public void onPageSelected(int position) {
        mCurrentItem = position;

        if (null != mTitleLists && mTitleLists.size() > 0
                && null != mTopNewsTitle) {
            mTopNewsTitle.setText(mTitleLists.get(position));
        }

        if (null != mDotLists && mDotLists.size() > 0) {
            mDotLists.get(position).setBackgroundResource(R.drawable.dot_focus);
            mDotLists.get(oldPosition).setBackgroundResource(
                    R.drawable.dot_normal);
        }
        oldPosition = position;
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = (int) ev.getX();
                downY = (int) ev.getY();
                // isMove = false;
                break;

            case MotionEvent.ACTION_MOVE:

                int currentX = (int) ev.getX();
                int currentY = (int) ev.getY();

                if (Math.abs(currentX - downX) > Math.abs(currentY - downY)) {
                    // 左右滑動viewPage

                    isMove = false;
                } else {
                    // 上下滑動listview
                    isMove = true;
                }

                break;
        }
        // 請求父類不要攔截我
        getParent().requestDisallowInterceptTouchEvent(!isMove);

        return super.dispatchTouchEvent(ev);
    }

    private class RollViewPagerAdapter extends PagerAdapter {

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {

            container.removeView((View) object);
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View view = View.inflate(mContext, R.layout.viewpager_item, null);
            ImageView image = (ImageView) view.findViewById(R.id.image);
            BitmapUtils.display(mContext, image, mImageLists.get(position));
            container.addView(view);
            return view;
        }

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

        @Override
        public boolean isViewFromObject(View arg0, Object arg1) {
            return arg0 == arg1;
        }

    }

    /**
     * 設定輪播圖上面的標題
     *
     * @param mTopNewsTitle
     * @param mTitleLists
     */
    public void setTextTitle(TextView mTopNewsTitle, List<String> mTitleLists) {
        if (null != mTopNewsTitle && null != mTitleLists && mTitleLists.size() > 0) {
            this.mTopNewsTitle = mTopNewsTitle;
            this.mTitleLists = mTitleLists;
            mTopNewsTitle.setText(mTitleLists.get(0));
        }

    }

    /**
     * 設定背景圖片
     *
     * @param mImageLists
     */
    public void setImageRes(List<String> mImageLists) {
        this.mImageLists = mImageLists;
    }

    private class Task implements Runnable {

        @Override
        public void run() {
            mCurrentItem = (mCurrentItem + 1) % mImageLists.size();
            handler.obtainMessage().sendToTarget();
        }

    }

    private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            RollViewPager.this.setCurrentItem(mCurrentItem, false);
            start();
        }
    };

    private ViewPageOnTouchListener mViewPageOnTouchListener;

    public interface ViewPageOnTouchListener {
        public void onViewPageClickListener();
    }

    public void setViewPageOnTouchListener(ViewPageOnTouchListener viewPageOnTouchListener) {
        mViewPageOnTouchListener = viewPageOnTouchListener;
    }
}

5. 開源專案

關於我

License

Copyright 2015 AllenIverson

Copyright 2012 Jake Wharton
Copyright 2011 Patrik Åkerfeldt
Copyright 2011 Francisco Figueiredo Jr.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.