Android自定义View(七)--很low的bannerView

来源:互联网 发布:数据库系统是由数据库 编辑:程序博客网 时间:2024/05/17 12:04

最近公司的项目需要实现类似淘宝、京东首页的广告banner,作为一个专业的“拷贝型”程序猿,在github上搜了一下,还是挺多的,其中还有两个比较好的,扩展性和特效都不错,看得我很是羡慕啊,有兴趣的童鞋请移步:

1.FlycoBanner_Master

2.Android-ConvenientBanner

作为一个长期“拷贝”的程序猿,偶尔还是有点小失落的,偶尔也会有大神梦,即使那么遥不可及。。。
于是乎,在一个月黑风高的夜晚,有史以来最low的广告banner诞生了。

先谈谈整体的思路吧,看到有些大神用AdapterView实现的,而我这种渣,首先想到的就是viewpager,虽然viewpager没有那么完美,不过能勉强将就也还是极好的。

当然只有viewpager是不够的,还有viewpager上面的那几个小点点,这个我就更简单粗暴的用一个Layout装载了结果imageview,然后viewpager改变item的时候,改变小点点的图片就可以啦。

还有一个问题就是循环播放啦,这个就要从viewpager的adapter入手了,上网查了很多,得到的结论就是在adapter的getCount方法上做手脚,即返回一个很大的数,使viewpager的item数量大于你看到的实际数量,而多的item中显示与前面item相同的内容,这样看起来就是循环的啦。

剩下的要解决自动循环就更简单啦,管你用timer还是handler还是thread都可以简单搞定。最后要解决的就是使这个东西用起来比较简单,所以我就简单的对它进行了一层小包装。

主要的视图类

package com.drivingassisstantHouse.library.widget.bannerview;import android.content.Context;import android.content.res.TypedArray;import android.support.annotation.NonNull;import android.support.v4.view.PagerAdapter;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.animation.AccelerateInterpolator;import android.view.animation.Interpolator;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.RelativeLayout;import android.widget.Scroller;import com.drivingassisstantHouse.library.R;import com.drivingassisstantHouse.library.tools.SLog;import com.drivingassisstantHouse.library.tools.ToolUnit;import java.lang.reflect.Field;import java.util.ArrayList;/** * 包名:com.drivingassisstantHouse.library.widget.bannerview * 描述:广告banner * 创建者:yankebin * 日期:2016/2/27 */public class BannerView extends RelativeLayout {    public static final int BANNER_TYPE_GUIDE = 1;    public static final int BANNER_TYPE_ADVERT = BANNER_TYPE_GUIDE + 1;    protected int type = BANNER_TYPE_GUIDE;    private BaseBannerViewpager viewPager;    private LinearLayout indicator;    private boolean isAutoLoop = false;    private long loopDelayTime = 4000;    private long scrollDuration=1200;    private ArrayList<ImageView> dots = new ArrayList<>();    public BannerView(Context context) {        super(context);        init();    }    public BannerView(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.BannerView);        type = typedArray.getInt(R.styleable.BannerView_bannerType, BANNER_TYPE_GUIDE);        isAutoLoop = typedArray.getBoolean(R.styleable.BannerView_autoPlay, false);        loopDelayTime = typedArray.getInt(R.styleable.BannerView_loopTime, 4000);        scrollDuration=typedArray.getInt(R.styleable.BannerView_scrollDuration, 1200);        if (null != typedArray) {            typedArray.recycle();        }        init();    }    @Override    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {        super.onVisibilityChanged(changedView, visibility);        if (visibility != VISIBLE) {            removeCallbacks(autoRunner);        } else {            if (isAutoLoop) {                startAutoPlay();            }        }    }    private Runnable autoRunner = new Runnable() {        @Override        public void run() {            if (!isAutoLoop) {                return;            }            int position=viewPager.getCurrentItem();            viewPager.setCurrentItem(++position, true);            postDelayed(this, loopDelayTime);        }    };    private Runnable indicatorRunner=new Runnable() {        @Override        public void run() {            int currentPosition = viewPager.getCurrentItem();            for (int i = 0; i < dots.size(); i++) {                ImageView imageView = dots.get(i);                if (currentPosition % dots.size() == i) {                    imageView.setImageResource(R.drawable.banner_dot_shape_selected);                } else {                    imageView.setImageResource(R.drawable.banner_dot_shape_normal);                }            }        }    };    public void setIsAutoLoop(boolean isLoop) {        this.isAutoLoop = isLoop;    }    public boolean isAutoLoop() {        return isAutoLoop;    }    public void setBannerAdapter(PagerAdapter adapter) {        viewPager.setAdapter(adapter);    }    private void init() {        viewPager = new BaseBannerViewpager(getContext());        viewPager.setLayoutParams(new LayoutParams(-1, -1));        indicator = new LinearLayout(getContext());        LayoutParams params = new LayoutParams(-2, -2);        params.addRule(ALIGN_PARENT_BOTTOM);        params.addRule(CENTER_HORIZONTAL);        params.bottomMargin = 10;        indicator.setLayoutParams(params);        indicator.setOrientation(LinearLayout.HORIZONTAL);        addView(viewPager);        addView(indicator);        initPagerListener();    }    private void initPagerListener() {        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {            @Override            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {            }            @Override            public void onPageSelected(int position) {                changeDotsColors();            }            @Override            public void onPageScrollStateChanged(int state) {            }        });    }    private void initDots(int size) {        if (size <= 0) {            throw new IllegalArgumentException("size必须大于0");        }        removeCallbacks(autoRunner);        dots.clear();        LinearLayout.LayoutParams pointViewParams = new LinearLayout.LayoutParams(                LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);        pointViewParams.setMargins(ToolUnit.dipTopx(8), 0,                ToolUnit.dipTopx(8), ToolUnit.dipTopx(8));        for (int i = 0; i < size; i++) {            ImageView pointView = new ImageView(getContext());            pointView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);            pointView.setLayoutParams(pointViewParams);            dots.add(pointView);            indicator.addView(pointView);        }        changeDotsColors();        if (isAutoLoop) {            startAutoPlay();        }    }    private void startAutoPlay() {        removeCallbacks(autoRunner);        postDelayed(autoRunner, loopDelayTime);    }    public void changeDotsColors() {       postDelayed(indicatorRunner,scrollDuration+500);    }    private class BaseBannerViewpager extends ViewPager {        private int childId;        public class FixedSpeedScroller extends Scroller {            private int mDuration = (int)scrollDuration;            public FixedSpeedScroller(Context context) {                super(context);            }            public FixedSpeedScroller(Context context, Interpolator interpolator) {                super(context, interpolator);            }            @Override            public void startScroll(int startX, int startY, int dx, int dy, int duration) {                // Ignore received duration, use fixed one instead                super.startScroll(startX, startY, dx, dy, mDuration);            }            @Override            public void startScroll(int startX, int startY, int dx, int dy) {                // Ignore received duration, use fixed one instead                super.startScroll(startX, startY, dx, dy, mDuration);            }            public void setmDuration(int time) {                mDuration = time;            }            public int getmDuration() {                return mDuration;            }        }        public BaseBannerViewpager(Context context) {            super(context);            resetScroller(context);        }        public BaseBannerViewpager(Context context, AttributeSet attrs) {            super(context, attrs);            resetScroller(context);        }        private void resetScroller(Context context){            try {                Field field = ViewPager.class.getDeclaredField("mScroller");                field.setAccessible(true);                FixedSpeedScroller scroller = new FixedSpeedScroller(context,                        new AccelerateInterpolator());                field.set(this, scroller);            } catch (Exception e) {                SLog.e(e);            }        }        @Override        public boolean onInterceptTouchEvent(MotionEvent event) {            if (childId > 0) {                ViewPager pager = (ViewPager) findViewById(childId);                if (pager != null) {                    pager.requestDisallowInterceptTouchEvent(true);                }            }            return super.onInterceptTouchEvent(event);        }        public void setAllowChildMovement(int id) {            this.childId = id;        }        @Override        public void setAdapter(PagerAdapter adapter) {            initDots(((BaseBannerPagerAdapter)adapter).getRealCount());            super.setAdapter(adapter);        }    }}

viewpager的adapter

package com.drivingassisstantHouse.library.widget.bannerview;import android.util.SparseArray;import android.view.View;import android.view.ViewGroup;import java.util.ArrayList;/** * 包名:com.simpletour.client.activity * 描述:banner适配器 * 创建者:yankebin * 日期:2016/2/27 */public abstract class BaseBannerPagerAdapter<T> extends android.support.v4.view.PagerAdapter {    protected SparseArray<View> views = new SparseArray<>();    private boolean isLoop;    protected ArrayList<T> datas;    public BaseBannerPagerAdapter() {        datas = new ArrayList<>();    }    public BaseBannerPagerAdapter(ArrayList<T> datas) {        this.datas = datas;    }    @Override    public final int getCount() {        return isLoop ? Integer.MAX_VALUE : datas.size();    }    @Override    public Object instantiateItem(ViewGroup container, int position) {        position = position % datas.size();        View view = views.get(position);        if (view == null) {            view = newView(position % getCount());            views.put(position, view);        }        container.addView(view);        return view;    }    public void notifyUpdateView(int position) {        View view = updateView(views.get(position), position);        views.put(position, view);        notifyDataSetChanged();    }    public View updateView(View view, int position) {        return view;    }    public abstract View newView(int position);    public final int getRealCount() {        return datas.size();    }    public void subscribe(BannerView bannerView) {        isLoop =bannerView.isAutoLoop()|| bannerView.type == BannerView.BANNER_TYPE_ADVERT;        bannerView.setBannerAdapter(this);    }}

一些自定义属性

<declare-styleable name="BannerView">        <attr name="autoPlay" format="boolean"/>        <attr name="bannerType" format="integer">            <flag name="typeGuide" value="1"/>            <flag name="typeAdvert" value="2"/>        </attr>        <attr name="loopTime" format="integer"/>        <attr name="scrollDuration" format="integer"/>    </declare-styleable>

代码里调用

首先定义好xml文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent">    <com.drivingassisstantHouse.library.widget.bannerview.BannerView        xmlns:banner="http://schemas.android.com/apk/res-auto"        android:layout_weight="1"        banner:autoPlay="true"        banner:loopTime="3000"        banner:bannerType="typeAdvert"        banner:scrollDuration="800"        android:id="@+id/bannerView"        android:layout_width="match_parent"        android:layout_height="0dp">    </com.drivingassisstantHouse.library.widget.bannerview.BannerView></LinearLayout>

其次实现BaseBannerPagerAdapter

 private class MBannerPagerAdapter extends BaseBannerPagerAdapter<String> {        public MBannerPagerAdapter() {            super(imageUrlList);            initImageLoader();        }        private void initImageLoader() {        }        @Override        public boolean isViewFromObject(View view, Object object) {            return null != object && object == view;        }        @Override        public void destroyItem(ViewGroup container, int position, Object object) {            container.removeView(views.get(position % views.size()));        }        @Override        public View newView(final int position) {            ImageView imageView = new ImageView(GuideActivity.this);            imageView.setLayoutParams(new ViewGroup.LayoutParams(-1, -1));            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);            ImageLoader.getInstance().displayImage(                    datas.get(position),                    imageView);            imageView.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    Intent intent=new Intent(GuideActivity.this,FloatActivity.class);                    intent.putExtra("uri", imageUrlList.get(position));                    Intent newIntent=new Intent(GuideActivity.this,PayDemoActivity.class);                    intent.putExtra("intent",newIntent);                    startActivity(intent);                }            });            return imageView;        }    }

最后

 new MBannerPagerAdapter().subscribe(bannerView);

这个效果和淘宝、京东的还有差距:

1.对于用户干预滑动的处理,我所能想到就是在touch事件中控制autorunner的执行,至于实现的细节,我还没有想好怎么去弄得更完美。

2.圆点指示器的实现方式,要是着色的圆点可以随viewpager相同的效果滑动而不是瞬间改变颜色就更好了。这个效果我也在viewpager的listener的onpagescrolled方法里尝试过了,但是当人为干预后,圆点就会错位,目前还没想到办法解决,希望有大神可以指点一二。

1 0
原创粉丝点击