广告条的实现ViewPager,左右滑动,切换图片
ViewPager(Pager寻呼机 Page页):这个控件不是安卓系统原生态的,虽然是第三方jar包,但是也是谷歌提供的,在android.support.v4.view.ViewPager下。
代码工程目录如下: 注意:viewpager显示的界面可以是任意视图,也可以是任意布局文件,还可以在布局文件中添加ListView,也就实现了即上下滑又左右滑,并且还不影响ListView的单击事件. 不过下面给出的例子显示的都是图片
代码如下:
import java.util.ArrayList; import android.os.Bundle; import android.app.Activity; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.LinearLayout.LayoutParams; import android.widget.TextView; /** 如果报这个类没有找到异常: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.view.ViewPager" 解决方法见图: */ public class MainActivity extends Activity { private ViewPager viewPager;//图片滑动的控件 private TextView textView;//图片上显示的文字 private LinearLayout pointGroup;//滑动的指示 private int[] imageArr={R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e}; private String[] textArr={"第一张显示的文字","第二张显示的文字","第三张显示的文字","第四张显示的文字","第五张显示的文字",}; private ArrayList<ImageView> imgList; private int lastPointPosition;//上一个页面的位置索引 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewPager = (ViewPager) findViewById(R.id.viewPager); textView = (TextView) findViewById(R.id.textView); pointGroup = (LinearLayout) findViewById(R.id.point_group); imgList=new ArrayList<ImageView>(); for (int i=0;i<imageArr.length;i++) { //初始化图片 ImageView image=new ImageView(this); image.setBackgroundResource(imageArr[i]); imgList.add(image); //添加图片的指示点 ImageView point=new ImageView(this); LinearLayout.LayoutParams params=new LayoutParams(10,10);//布局参数,point的布局宽与高 params.rightMargin=10;//右边距 point.setLayoutParams(params);//设置布局参数 point.setBackgroundResource(R.drawable.point_bg);//point_bg是根据setEnabled的值来确定形状的 if(i==0){ point.setEnabled(true);//初始化的时候设置第一张图片的形状 }else{ point.setEnabled(false);//根据该属性来确定这个图片的显示形状 } pointGroup.addView(point);//将该指示的图片添加到布局中 } textView.setText(textArr[0]);//将第一次显示的文本初始化到视图中 //添加适配器 viewPager.setAdapter(new MyPagerAdapter()); //为viewPager设置监听 viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { //页面改变的时候调用(稳定),positon表示被选中的索引 @Override public void onPageSelected(int position) { textView.setText(textArr[position]);//设置文字描述内容 //改变指示点的状态 pointGroup.getChildAt(position).setEnabled(true);//将当前点enbale设置为true pointGroup.getChildAt(lastPointPosition).setEnabled(false);//将上一个点设置为false lastPointPosition=position; } //页面正在滑动的时候调用,position指的是左侧页面的索引,positionOffset代表偏移量[0,1]的范围,positionOffsetPixels也是偏移量,不过是像素点的偏移量 范围[0,显示的控件的绝对长度] @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override //页面滚动状态发送改变的时候回调 public void onPageScrollStateChanged(int state) { //当手指点击屏幕滚动的时状态码为1,当手指离开viewpager自动滚动的状态码为2,自动滚动选中了显示了页面的时候状态码为0 } }); } /** *ViewPager的适配器,原理: *它最多只会创建三个图片(即当前屏幕显示的这张图片与该图片的左右两张图片,当滑动的时候,就会把多余的销毁掉,需要的创建出来) */ private class MyPagerAdapter extends PagerAdapter{ /** * 获得页面的总数 */ @Override public int getCount() { return imageArr.length; } /** * 判断view和object的对应关系,如果当前要显示的控件是来之于instantiateItem方法创建的就显示,否则不显示 * object 为instantiateItem方法返回的对象 * 如果为false就不会显示该视图 */ @Override public boolean isViewFromObject(View view, Object object) { System.out.println("view:"+view); System.out.println("object:"+object); return view==object; } /** * 实例化下一个要显示的子条目,获取相应位置上的view,这个为当前显示的视图的下一个需要显示的控件 * container view的容器,其实就是viewager自身 * position ViewPager相应的位置 */ @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(imgList.get(position)); System.out.println("创建一个视图"); return imgList.get(position); } /** * 销毁一个子条目,object就为instantiateItem方法创建的返回的对象,也是滑出去需要销毁了的视图对象 */ @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); object=null; System.out.println("销毁一个视图"); } } }
类找不到异常的解决办法: 如果还异常就把android-support-v4.jar Top到置顶
布局文件:activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <!-- 广告条布局(视图页) --> <android.support.v4.view.ViewPager android:layout_width="match_parent" android:layout_height="200dp" android:id="@+id/viewPager" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#33000000" android:orientation="vertical" android:layout_alignBottom="@id/viewPager"> <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textColor="@android:color/white" android:textSize="20sp" android:text="默认文字"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:id="@+id/point_group"> </LinearLayout> </LinearLayout> </RelativeLayout>
关于指示器的文件:
1. point_nomal.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <!-- 一个圆形的图形 --> <size android:width="5dp" android:height="5dp"/> <solid android:color="#55000000"/> </shape>
2.point_focured.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <size android:width="5dp" android:height="5dp"/> <solid android:color="#aaffffff"/> </shape>
3. point_bg.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" > <!-- 可使用就为point_focured形状, 否则为point_nomal形状 所以java代码中根据setEnabled(false)方法来确定显示什么形状--> <item android:drawable="@drawable/point_nomal" android:state_enabled="false"></item> <item android:drawable="@drawable/point_focured" android:state_enabled="true"></item> </selector>
效果图如下:
循环滑动功能与自动滑动功能的实现以及点击指示器显示对应的页面(在上面的java代码中进行修改,代码如下):
import java.util.ArrayList; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.LinearLayout.LayoutParams; import android.widget.TextView; /** 如果报这个类没有找到异常: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.view.ViewPager" 解决方法见图. 这里和上面的不同: 1.将当前显示的图片的指示器setEnabled(false),让当前的不可点击,其他的可以点击 2.为指示器设置了单击事件,利用到了tag 3.将数据的初始化抽取成了一个方法 新增功能: 1.可以点击指示器,ViewPager跳转到对应的图片显示 2.循环显示,自动滑动 ViewPager两个比较重要的方法: viewPager.setCurrentItem(tag);//指定显示哪个页面 viewPager.getCurrentItem();//获取当前显示的界面的索引 */ public class MainActivity extends Activity { private ViewPager viewPager;//图片滑动的控件 private TextView textView;//图片上显示的文字 private LinearLayout pointGroup;//滑动的指示 /** * 装图片的资源id */ private int[] imageArr={R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e}; private String[] textArr={"第一张显示的文字","第二张显示的文字","第三张显示的文字","第四张显示的文字","第五张显示的文字",}; private ArrayList<ImageView> imgList; private int lastPointPosition;//上一个页面的位置索引,也是上一个指示器的索引 /** * 为true才发生消息给handler,避免程序退出后还一直发送消息给handler */ private boolean isRuning=true; /** * 用于实现自动滑动 */ private Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { if(msg.what==1 && isRuning){ //收到消息,开始滑动 int currentItem = viewPager.getCurrentItem();//获取当前显示的界面的索引 //如果当前显示的是最后一个页面,就显示第一张,否则显示下一张 if(currentItem==imgList.size()-1){ viewPager.setCurrentItem(0); }else{ viewPager.setCurrentItem(currentItem+1); } //2ms后再发送消息,实现循环 handler.sendEmptyMessageDelayed(1, 5000); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewPager = (ViewPager) findViewById(R.id.viewPager); textView = (TextView) findViewById(R.id.textView); pointGroup = (LinearLayout) findViewById(R.id.point_group); initData();//初始化 //添加适配器 viewPager.setAdapter(new MyPagerAdapter()); //为viewPager设置监听 viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { //页面改变的时候调用(稳定),positon表示被选中的索引 @Override public void onPageSelected(int position) { textView.setText(textArr[position]);//设置文字描述内容 //改变指示点的状态 pointGroup.getChildAt(position).setEnabled(false);//将当前点enbale设置为false,让当前的指示器点击无效 pointGroup.getChildAt(lastPointPosition).setEnabled(true);//将上一个点设置为true lastPointPosition=position; } /*当页面正在滚动的时候调用 * int position, 页面的索引,指向的是左侧页面的索引 * float positionOffset, 表示偏移量, 值为 0- 1 ,0表示相对于左侧页面没有偏移 , 1表示相对于左侧页面偏移1个单位长度(完全偏移) int positionOffsetPixels 表示偏移量, 值为 0-控件的绝对长度 */ @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } /* 当页面滚动状态改变的时候调用 * 当手指点击屏幕在屏幕上滚动的时候 状态为1 * 当手指离开,viewpager自动 滚动 选中页面时 状态为2 * 当手指离开,自动 选中上页面时 状态为0 */ @Override public void onPageScrollStateChanged(int state) { } }); //发送第一条消息给handler,实现循环 handler.sendEmptyMessageDelayed(1, 5000); } /** * 初始化数据,将图片和指示器都创建出来添加到集合 * 这里通过数组的长度,动态添加图片和指示器,有利于从网络上获取数据显示 */ private void initData(){ imgList=new ArrayList<ImageView>(); for (int i=0;i<imageArr.length;i++) { //初始化图片 ImageView image=new ImageView(this); image.setBackgroundResource(imageArr[i]); imgList.add(image); //添加图片的指示点 final ImageView point=new ImageView(this); LinearLayout.LayoutParams params=new LayoutParams(20,20);//布局参数,point的布局宽与高 params.rightMargin=10;//右边距 point.setLayoutParams(params);//设置布局参数 point.setBackgroundResource(R.drawable.point_bg);//point_bg是根据setEnabled的值来确定形状的 if(i==0){ point.setEnabled(false);//初始化的时候设置第一张图片的形状 }else{ point.setEnabled(true);//根据该属性来确定这个图片的显示形状 } point.setClickable(true);//设置为可点击 //为point设置单击事件,实现点击后ViewPager显示对应的图片 point.setTag(i);//设置标记,好知道点击的指示器的索引 point.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int tag = (Integer) point.getTag();//获取这个指示器的标记 viewPager.setCurrentItem(tag);//设置当前显示的为第tag张图片,执行后会调用监听事件,所以指示器颜色的变化不需要在这里处理 } }); pointGroup.addView(point);//将该指示的图片添加到布局中 } textView.setText(textArr[0]);//将第一次显示的文本初始化到视图中 } /** *ViewPager的适配器,原理: *它最多只会创建三个图片(即当前屏幕显示的这张图片与该图片的左右两张图片,当滑动的时候,就会把多余的销毁掉,需要的创建出来) */ private class MyPagerAdapter extends PagerAdapter{ /** * 获得页面的总数 */ @Override public int getCount() { return imgList.size(); } /** * 判断view和object的对应关系,如果当前要显示的控件是来之于instantiateItem方法创建的就显示,否则不显示 * object 为instantiateItem方法返回的对象 * 如果为false就不会显示该视图 */ @Override public boolean isViewFromObject(View view, Object object) { return view==object; } /** * 实例化下一个要显示的子条目,获取相应位置上的view,这个为当前显示的视图的下一个需要显示的控件 * container view的容器,其实就是viewager自身 * position ViewPager相应的位置 */ @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(imgList.get(position)); return imgList.get(position); } /** * 销毁一个子条目,object就为instantiateItem方法创建的返回的对象,也是滑出去需要销毁了的视图对象 */ @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); object=null; } } /** * 当程序退出时,结束handler消息的发送 */ @Override protected void onDestroy() { super.onDestroy(); isRuning=false; } }