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方法里尝试过了,但是当人为干预后,圆点就会错位,目前还没想到办法解决,希望有大神可以指点一二。
- Android自定义View(七)--很low的bannerView
- 自定义BannerView,显示下个一个view部分界面
- Android-简单的轮播图控件BannerView
- Android 从0开始自定义控件之 View 的 measure 过程(七)
- Android开发-自定义View-AndroidStudio(七)popupwindow
- 自定义类似优酷首页的BannerView幻灯片展示
- 自定义类似优酷首页的BannerView幻灯片展示
- android BannerView实现自动轮播广告的用法(参考自github)
- Android -自定义view(三)自定义view的流程
- android的自定义View
- Android自定义View研究(七)--XML中布局自定义View时View触摸原点问题
- Android自定义View研究(七)--XML中布局自定义View时View触摸原点问题
- Android自定义View之七色环颜色采集器: 续我未完的大学梦 !
- Android的自定义View(2)
- android自定义View二(View的种类)
- android Notification自定义view(view不更新的问题)
- android 自定义View之View的测量(onMeasure()方法)
- Android自定义View实战(会波动的View)
- 提升用户体验之A/B测试(5)——linux安装python(pip)插件
- 《fstab文件字段详解-原理精讲-实战反刍知识回顾》
- 新建并配置Maven工程
- Educational Codeforces Round 9 C. The Smallest String Concatenation(字符串排序)
- 源码编译安装tengine
- Android自定义View(七)--很low的bannerView
- android如何完全root
- POJ-1509 Glass Beads (字符串最小表示法&后缀自动机)
- VS2010环境下C#如何建立与SQLServer的连接并获取数据
- 华为oj iNOC产品部--完全数计算
- 解决VC6.0出现“ Microsoft(R)Developer Studio已停止工作”的问题
- 18. 4Sum
- 主题模型
- ResourcesUtil. getIdentifier