一步一步实现自定义控件(三)
2016-10-07 17:39
316 查看
前言
今天我们来实现的是第二个案例,广告图片轮播效果图
实现
OK 接下来我们就是一步一步实现这个效果我们观察这个效果图,其实它主要可以分为三步:
让图片滑动起来
让图片和文字,指示器对应起来
让轮播器无限循环
好了,接下来我们就按照我们分析的三步走
让图片滑动起来
第一步就是让我们的图片滑动起来,这里用的是一个v4包下的控件:ViewPager (不熟悉的童鞋可以自行去百度查下),下面我也会简单介绍下这个控件的使用OK,我们在我们的主布局中先添加一个ViewPager
<android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="160dp"/>
这里得说明下,用这个控件你必须要把全路径写下来,就是带包名的
紧接着我们会发现,我们的效果图下面还有一小条灰色的区域,里面要放我们的指示器的,所以我们还要在我们的布局中要把指示器的xml也添加进去,这里用相对布局最好,所以就直接把整个的布局贴出来了
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hfs.lunboadvertisedemo.MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="160dp">
<android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="160dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:background="#66000000"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:text="天王盖地虎,宝塔镇河妖"
android:textColor="@android:color/white"/>
<LinearLayout
android:id="@+id/ll_point_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:orientation="horizontal">
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
Ok,整个布局贴出来之后,我们就要开始实现我们的第一个功能了,同时也简单介绍下ViewPager
我们首先要新建一个数组,这个数组里面存放的是我们要显示的图片资源
mImageResids = new int[]{R.mipmap.a, R.mipmap.b, R.mipmap.c, R.mipmap.d, R.mipmap.e};
同时ViewPager里面我们这里放的是ImageView来显示图片,同时ImageView的个数是和我们定义的这个数组的长度相同的,所以这里我们还要定义一个集合,同时遍历我们这个数组,把ImageView添加进集合中
//初始化要展示的ImageView mImageViewArrayList = new ArrayList<>(); for (int i = 0; i < mImageResids.length; i++) { imageView = new ImageView(this); imageView.setBackgroundResource(mImageResids[i]); mImageViewArrayList.add(imageView); }
之后要写一个类去继承PagerAdapter,同时重写4个方法(有点类似ListView的用法)
class MyAdapter extends PagerAdapter { @Override public int getCount() { return Integer.MAX_VALUE; } //3.指定复用的判断逻辑,固定写法 @Override public boolean isViewFromObject(View view, Object object) { //当滑倒新的条目.又返回来,view是否可以被复用 return view == object; } //1.返回要显示的条目内容 创建条目 //container 容器 ViewPager //position 当前要是显示条目位置 @Override public Object instantiateItem(ViewGroup container, int position) { ImageView imageView = mImageViewArrayList.get(position); //a.把View对象添加到contain中 container.addView(imageView); //b.把View对象返回给框架 return imageView;//必须重写 这里是源码中建议的,有兴趣的童鞋可以去源码中查看下 } //2.销毁条目 @Override public void destroyItem(ViewGroup container, int position, Object object) { //object要销毁的对象 container.removeView((View) object); } }
这里补充下,ViewPager默认是加载三张图片的,就是当前图片加上左右各一个,其实我们也可以通过代码来修改左右显示的个数
//参数的个数就是左右显示条目的个数 setOffscreenPageLimit(xxx);
OK,到这里我们的第一步基本就完成了
让图片和文字,指示器对应起来
第二步就是把图片和我们的指示器对应起来,也就是灰色框中的小圆点.OK,首先我们得把这个小圆点加上把,通过代码的形式动态加进去,个数显然就是我们的图片的个数,这样的话我们在遍历图片资源的时候,就把小圆点(指示器)加进去就Ok了
这个圆点我们就自己画出来就好了,亮的表示可用,灰色的表示不可用:
可用:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <corners android:radius="5dp"/> <solid android:color="#FFFFFF"/> </shape>
不可用:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <corners android:radius="5dp"/> <solid android:color="@android:color/darker_gray"/> </shape>
然后给他们加到xml中:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="true" android:drawable="@drawable/shape_point_enable_bg"/> <item android:state_enabled="false" android:drawable="@drawable/shape_point_noable_bg"/> </selector>
指示器画出来之后,就可以添进去了:
private ArrayList<View> mViewPoints; mViewPoints = new ArrayList<>(); ImageView imageView; View pointView; for (int i = 0; i < mImageResids.length; i++) { imageView = new ImageView(this); imageView.setBackgroundResource(mImageResids[i]); mImageViewArrayList.add(imageView); //TODO 2加指示器 pointView = new View(this); pointView.setBackgroundResource(R.drawable.select_point_bg); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(5, 5);//设置大小 if (i != 10) { params.leftMargin = 10;//设置间隔 } pointView.setEnabled(false); mLinearLayout.addView(pointView, params);//没给宽高指示器会被拉伸 }
这里注意下,一定要用LinearLayout下的LayoutParams,不要用ViewGroup下的
OK,指示器添加成功了,默认都不是选中的,但是我们发现我们的效果图默认第一个指示器是选中状态,所以我们要把第一个设置为选中状态
mLinearLayout.getChildAt(0).setEnabled(true);
还有就是在滑动图片的时候,下面的指示器要跟着改变状态,这里就需要对ViewPager做滑动监听了,重写三个方法:
mViewPager.addOnPageChangeListener(this);//设置滚动监听 @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { //滚动时调用 } @Override public void onPageSelected(int position) { //新的条目被选中时调用 mTextView.setText(contentDescs[position]);//文字也要跟着变化 for (int i = 0; i < mLinearLayout.getChildCount(); i++) { mLinearLayout.getChildAt(i).setEnabled(false); } mLinearLayout.getChildAt(position).setEnabled(true); } @Override public void onPageScrollStateChanged(int state) { //滚动状态变化时调用 }
OK,这样我们的第二个功能也实现了
让轮播器无限循环
现在就剩下最后一个功能了,让我们的控件无限轮播这里要说明下,现在好多类似控件的无限循环都是伪无限循环,就是把adapter中getCount方法的返回值设置一个很大的数,这样用户怎么滑也滑不到头,感觉就是无限循环一样,我们这里也是用的这个方法
@Override public int getCount() { return Integer.MAX_VALUE; }
这个值如果你不停的滑动,一秒一次的话大约60多年…..
但是这里还有个问题,在adapter的instantiateItem()方法中,我们用mImageViewArrayList.get(position);拿到对应的ImageView,但是我们实际只有5个,而我们getCount()的返回值确大于5个,所以如果这里不改的话就出报角标越界的错误,所以我们要重新计算这个position,要根据新的position拿到ImageView
int newPositon = position % mImageViewArrayList.size(); ImageView imageView = mImageViewArrayList.get(newPositon);
还有一个地方也要改以下,就是滑动监听的onPageSelected()方法,也就是指示器的索引
int newPositon = position % mImageViewArrayList.size(); mTextView.setText(contentDescs[newPositon]);
OK,上面说的都是向右无限滑动的解决办法,那么怎么实现向左无限滑动呢?
我们可以让ViewPager一开始跳到中间的某个位置,因为我们getCount()返回值很大,即使跳到中间,这个位置也很大,所以就可以无限向左划动了
//默认设置到中间的莫个位置 int position = Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2 % mImageViewArrayList.size()); mViewPager.setCurrentItem(position);
这里有个小BUG,有的时候我一点击图片就切换了,如果出现这个BUG,就把Integer.MAX_VALUE
换成一个很大的数,比如5000000等等
一般轮播都是自动的,所以我们要让它开启自动轮询,可以有好多办法实现,这里我们用一个简单的办法
//TODO 3自动轮询 //开启轮询 new Thread(new Runnable() { @Override public void run() { isRunning=true; while (isRunning) { try { Thread.sleep(1000 * 2); } catch (InterruptedException e) { e.printStackTrace(); } runOnUiThread(new Runnable() { @Override public void run() { //往下跳一位 mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1); } }); } } }).start();
解释下isRunning:
我们发现我们退出之后,它还在跑,因为我们设置的是死循环,所以我们要加一个boolean值做判断,在界面销毁时,把它置为false,
@Override protected void onDestroy() { super.onDestroy(); isRunning=false; }
OK这样我们的这个轮播控件就做完了
源码:
https://github.com/Greathfs/LunBoAdvertiseDemo
相关文章推荐
- 一步一步实现自定义控件(四)
- 一步一步实现自定义控件(一)
- 一步一步实现自定义控件(二)
- 一步一步SharePoint 2007之二十一:解决实现注册用户后,自动具备访问网站的权限的问题(3)——创建用户
- 一步一步SharePoint 2007之十二:实现Form认证(2)——创建添加管理帐户的工程
- 一步一步SharePoint 2007之十九:解决实现注册用户后,自动具备访问网站的权限的问题(1)——配置Provider
- 一步一步SharePoint 2007之十五:实现Form认证(5)——更改认证的Provider
- 一步一步SharePoint 2007之十一:实现Form认证(1)——生成用户数据库
- 利用ASP.NET服务器端自定义控件实现XML文件中还原表单
- Blend中如何自定义控件模版,实现“vista button动画效果”(附图)
- 如何在.NET自定义控件中实现自己的事件(转)
- 一步一步用Delphi6实现Web Service
- asp.net控件开发基础(10) --------再谈属性,实现自定义控件集合属性
- Asp.net 2.0 自定义控件开发[实现自动计算功能(AutoComputeControl)][示例代码下载]
- AjaxPanel自定义控件实现页面无刷新数据交互(做了个示例程序, 效果确实比较Cool, 用法非常简单! )(示例代码下载)
- 一步一步SharePoint 2007之二十:解决实现注册用户后,自动具备访问网站的权限的问题(2)——配置Role
- ASP自定义控件的两种实现方法
- 一步一步实现数据库到类的自动化映射(二) 类层次的设计 类的实现
- 一步一步SharePoint 2007之二十二:完美解决实现Form认证后无法再用SharePoint Designer编辑网站的问题
- Asp.net 2.0 自定义控件开发[实现GridView多行表头固定表体滚动效果]