Android ViewPager使用小结
来源:互联网 发布:sqlserver可视化工具 编辑:程序博客网 时间:2024/06/10 02:21
Viewpager在项目中随处可见,通常用来做引导页、图片轮翻,或结合Fragment搭建Tab+Fragment+ViewPager项目整体框架。简单总结了一下ViewPager的常见使用方式,由于比较简单直接上代码!
1、引导页实现
引导页一般分为两种,左右滑动引导,上下滑动引导,通过ViewPager轻松实现左右滑动的引导页,并且实现引导点跟随滑动而移动的引导页。
效果图:
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" > <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" > </android.support.v4.view.ViewPager> <FrameLayout android:id="@+id/layout_frame" android:layout_width="match_parent" android:layout_height="40dp" android:layout_alignParentBottom="true" > <LinearLayout android:id="@+id/layout_point" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="horizontal" > </LinearLayout> </FrameLayout> <Button android:id="@+id/btn_go" android:layout_width="wrap_content" android:layout_height="35dp" android:layout_above="@id/layout_frame" android:layout_centerHorizontal="true" android:layout_marginBottom="30dp" android:background="@drawable/shape_white_blue_4" android:padding="5dp" android:text="立即进入" android:textColor="@android:color/white" android:textSize="14sp" android:visibility="gone" /></RelativeLayout>
引入v4包中的ViewPager,添加引导点的布局,其中FrameLayout包裹LinearLayout是因为,选中点(即亮点)需要跟随移动,当某个Pager被选中时选中点将该Pager之前的未选中点(即暗点)进行了遮挡,所以需要上下层关系,在布局中体现包裹关系。
MainActivity.java
/** * Created by magic on 2016年9月28日.引导点跟随移动的引导页 */public class MainActivity extends Activity implements OnPageChangeListener { ViewPager viewPager; FrameLayout layout_frame; LinearLayout layout_point; // 带颜色的引导点 ImageView img_colorPoint; Button btn_go; List<View> list_view = new ArrayList<View>(); List<ImageView> list_pointView = new ArrayList<ImageView>(); //ViewPager 适配器 ViewPagerAdapter adapter; // 两点之间间距 int pointSpacing; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initGuideView(); } /** * 初始化引导页相关 */ private void initGuideView() { //添加展示的View LayoutInflater inflater = LayoutInflater.from(this); list_view.add(inflater.inflate(R.layout.guide_one, null)); list_view.add(inflater.inflate(R.layout.guide_two, null)); list_view.add(inflater.inflate(R.layout.guide_three, null)); adapter = new ViewPagerAdapter(list_view); viewPager.setAdapter(adapter); //添加引导点 for (int i = 0; i < list_view.size(); i++) { ImageView point = new ImageView(this); //设置暗点 point.setBackgroundResource(R.drawable.img_guide_point); LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.setMargins(10, 0, 10, 0); point.setLayoutParams(lp); list_pointView.add(point); layout_point.addView(point); } //添加选中的引导点 img_colorPoint = new ImageView(MainActivity.this); //设置亮点 img_colorPoint.setBackgroundResource(R.drawable.img_guide_point_selected); LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); img_colorPoint.setLayoutParams(lp); layout_frame.addView(img_colorPoint); layout_frame.post(new Runnable() { @Override public void run() { //待布局绘制完毕 设置选中白点 的初始化位置 FrameLayout.LayoutParams l = (FrameLayout.LayoutParams) img_colorPoint.getLayoutParams(); l.leftMargin = list_pointView.get(0).getLeft(); img_colorPoint.setLayoutParams(l); } }); layout_point.post(new Runnable() { @Override public void run() { // 获取引导的之间的间隔 pointSpacing = layout_point.getChildAt(1).getLeft()- layout_point.getChildAt(0).getLeft(); } }); } private void initView() { viewPager = (ViewPager) findViewById(R.id.viewPager); layout_frame = (FrameLayout) findViewById(R.id.layout_frame); layout_point = (LinearLayout) findViewById(R.id.layout_point); btn_go = (Button) findViewById(R.id.btn_go); viewPager.setOnPageChangeListener(this); btn_go.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this,TwoActivity.class)); } }); } @Override public void onPageScrollStateChanged(int arg0) { } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { FrameLayout.LayoutParams l = (FrameLayout.LayoutParams) img_colorPoint .getLayoutParams(); //根据滑动动态设置左外边距 l.leftMargin = (int) (list_pointView.get(arg0).getLeft() + pointSpacing * arg1); img_colorPoint.setLayoutParams(l); } @Override public void onPageSelected(int arg0) { //根据Pager位置设置btn的显示 if (arg0 == list_view.size() - 1) { btn_go.setVisibility(View.VISIBLE); } else { btn_go.setVisibility(View.GONE); } }}
ViewPager的onPageScrolled(int arg0, float arg1, int arg2)回调在滑动过程中会一直调用,参数arg0 :当前页面,点击滑动的页面;arg1:当前页面偏移的百分比;arg2:当前页面偏移的像素位置 。有个这个方法就可以计算小白点的偏移位置了,两引导点之间间距相对两个Pager之间的间距即ViewPager的“宽度”,因此偏移百分比是相同的。
ViewPagerAdapter.java
/** * Created by magic on 2016年9月28日.ViewPager适配器 */public class ViewPagerAdapter extends PagerAdapter { private List<View> views; public ViewPagerAdapter(List<View> list) { super(); this.views = list; } // 从当前container中删除指定位置(position)的View @Override public void destroyItem(View container, int position, Object object) { ((ViewPager) container).removeView(views.get(position)); } // 第一:将当前视图添加到container中,第二:返回当前View @Override public Object instantiateItem(View container, int position) { // 将当前视图添加到container中 ((ViewPager) container).addView(views.get(position)); // 设置当前视图的唯一标示Key return views.get(position); } // getCount():返回要滑动的View的个数 @Override public int getCount() { return views.size(); } // 通过标识arg1找到view @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; }}
2、图片轮翻实现
图片轮翻和引导页代码几乎是一致的,只是添加了定时器,用于自动切换界面。
效果图:
activity_two.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" > <RelativeLayout android:layout_width="match_parent" android:layout_height="180dp" > <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" > </android.support.v4.view.ViewPager> <FrameLayout android:id="@+id/layout_frame" android:layout_width="match_parent" android:layout_height="40dp" android:layout_alignParentBottom="true" > <LinearLayout android:id="@+id/layout_point" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="horizontal" > </LinearLayout> </FrameLayout> </RelativeLayout></RelativeLayout>
TwoActivity.java
/** * Created by magic on 2016年9月28日.图片轮番 */public class TwoActivity extends Activity implements OnPageChangeListener { ViewPager viewPager; FrameLayout layout_frame; LinearLayout layout_point; // 带颜色的引导点 ImageView img_colorPoint; List<View> list_view = new ArrayList<View>(); List<ImageView> list_pointView = new ArrayList<ImageView>(); ViewPagerAdapter adapter; // 两点之间间距 int pointSpacing; //当前ViewPager选中位置 int pageSelect = 0; //定时器 Timer timer; Task task; @SuppressLint("HandlerLeak") private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { viewPager.setCurrentItem(pageSelect); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_two); initView(); initGuideView(); timer = new Timer(); task = new Task(); //设置定时延迟1000开始 时间周期1500 timer.schedule(task, 1000, 1500); } private void initGuideView() { LayoutInflater inflater = LayoutInflater.from(this); list_view.add(inflater.inflate(R.layout.guide_one, null)); list_view.add(inflater.inflate(R.layout.guide_two, null)); list_view.add(inflater.inflate(R.layout.guide_three, null)); adapter = new ViewPagerAdapter(list_view); viewPager.setAdapter(adapter); for (View view : list_view) { view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(TwoActivity.this,ThreeActivity.class)); } }); } for (int i = 0; i < list_view.size(); i++) { ImageView point = new ImageView(this); point.setBackgroundResource(R.drawable.img_guide_point); LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.setMargins(10, 0, 10, 0); point.setLayoutParams(lp); list_pointView.add(point); layout_point.addView(point); } img_colorPoint = new ImageView(TwoActivity.this); img_colorPoint .setBackgroundResource(R.drawable.img_guide_point_selected); LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); img_colorPoint.setLayoutParams(lp); layout_frame.addView(img_colorPoint); layout_frame.post(new Runnable() { @Override public void run() { FrameLayout.LayoutParams l = (FrameLayout.LayoutParams) img_colorPoint .getLayoutParams(); l.leftMargin = list_pointView.get(0).getLeft(); img_colorPoint.setLayoutParams(l); } }); layout_point.post(new Runnable() { @Override public void run() { // 获取引导的之间的间隔 pointSpacing = layout_point.getChildAt(1).getLeft() - layout_point.getChildAt(0).getLeft(); } }); } private void initView() { viewPager = (ViewPager) findViewById(R.id.viewPager); layout_frame = (FrameLayout) findViewById(R.id.layout_frame); layout_point = (LinearLayout) findViewById(R.id.layout_point); viewPager.setOnPageChangeListener(this); } @Override public void onPageScrollStateChanged(int arg0) { } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { System.out.println("arg0:" + arg0 + " arg1:" + arg1 + " arg2:" + arg2); FrameLayout.LayoutParams l = (FrameLayout.LayoutParams) img_colorPoint .getLayoutParams(); l.leftMargin = (int) (list_pointView.get(arg0).getLeft() + pointSpacing * arg1); img_colorPoint.setLayoutParams(l); } @Override public void onPageSelected(int arg0) { pageSelect = arg0; } /** * 定时任务类 */ class Task extends TimerTask { @Override public void run() { pageSelect++; if (pageSelect >= list_view.size()) { pageSelect = 0; } handler.sendEmptyMessage(pageSelect); } }}
ViewPagerAdapter.java同上~~~
3、图片循环轮翻实现
上面的图片轮翻可自动切换,也可手动滑动切换。但是存在一个问题就是当手动切换的时候滑动到第一个Pager或最后一个Pager时,再向前或向后滑动就不能滑了,这样的体验是不太好的 。
为了解决这个问题,自己冥思苦想,加上查找资源,无奈人丑脑笨,未能合理解决,利用ViewPager去做总会存在或多或少的bug,例如白屏、Pager数量影响滑动效果等问题。最后求助朋友,得到一前人写的自定义控件(该实现并非使用Viewpager,但和ViewPager实现图片轮翻效果一致就放一块整理了),完美解决了,哈哈~
效果图:
先上布局activity_three.xml
<?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="match_parent" android:orientation="vertical" > <RelativeLayout android:layout_width="match_parent" android:layout_height="180dp" > <com.magic.custom.MyPagerGalleryView android:id="@+id/mypager_galleryview" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:id="@+id/layout_point" android:layout_width="match_parent" android:layout_height="15dp" android:layout_alignParentBottom="true" android:layout_marginBottom="20dp" android:gravity="center_horizontal" android:orientation="horizontal" > </LinearLayout> </RelativeLayout></LinearLayout>
主界面ThreeActivity.java
/** * Created by magic on 2016年9月29日.图片轮翻循环效果 */public class ThreeActivity extends Activity { MyPagerGalleryView mypager_galleryview; LinearLayout layout_point; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_three); mypager_galleryview = (MyPagerGalleryView) findViewById(R.id.mypager_galleryview); layout_point = (LinearLayout) findViewById(R.id.layout_point); mypager_galleryview .start(this, new ArrayList<String>(), new int[] { R.drawable.img_guide_one, R.drawable.img_guide_two, R.drawable.img_guide_three }, 1500, layout_point, R.drawable.img_guide_point_selected, R.drawable.img_guide_point); }}
自定义控件:MyPagerGalleryView.java
/** * 无限滚动广告栏组件 */@SuppressWarnings("deprecation")public class MyPagerGalleryView extends Gallery implements android.widget.AdapterView.OnItemClickListener, android.widget.AdapterView.OnItemSelectedListener, OnTouchListener { /** 显示的Activity */ private Context mContext; /** 条目单击事件接口 */ private MyOnItemClickListener mMyOnItemClickListener; /** 图片切换时间 */ private int mSwitchTime; /** 自动滚动的定时器 */ private Timer mTimer; /** 圆点容器 */ private LinearLayout mOvalLayout; /** 当前选中的数组索引 */ private int curIndex = 0; /** 上次选中的数组索引 */ private int oldIndex = 0; /** 圆点选中时的背景ID */ private int mFocusedId; /** 圆点正常时的背景ID */ private int mNormalId; /** 图片资源ID组 */ private int[] mAdsId; /** 图片网络路径数组 */ private List<String> list; /** ImageView组 */ private List<ImageView> listImgs; /** 广告条上面textView控件 */ private TextView adgallerytxt; /** 广告条上的每一条文字的数组 */ private String[] txtViewpager; private ImageLoader il; public MyPagerGalleryView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public MyPagerGalleryView(Context context) { super(context); } public MyPagerGalleryView(Context context, AttributeSet attrs) { super(context, attrs); } /** * 对外开放方法 * * @param context * 显示的Activity ,不能为null * @param mris * 图片的网络路径数组 ,为空时 加载 adsId * @param adsId * 图片组资源ID ,测试用 * @param switchTime * 图片切换时间 写0 为不自动切换 * @param ovalLayout * 圆点容器 ,可为空 * @param focusedId * 圆点选中时的背景ID,圆点容器可为空写0 * @param normalId * 圆点正常时的背景ID,圆点容器为空写0 * @param adgallerytxt * 广告条上面textView控件 * @param txtViewpager * 广告条上的每一条文字的数组 * */ public void start(Context context, List<String> list, int[] adsId, int switchTime, LinearLayout ovalLayout, int focusedId, int normalId) { this.mContext = context; this.list = list; this.mAdsId = adsId; this.mSwitchTime = switchTime; this.mOvalLayout = ovalLayout; this.mFocusedId = focusedId; this.mNormalId = normalId; ininImages();// 初始化图片组 setAdapter(new AdAdapter()); this.setOnItemClickListener(this); this.setOnTouchListener(this); this.setOnItemSelectedListener(this); this.setSoundEffectsEnabled(false); this.setAnimationDuration(700); // 动画时间 this.setUnselectedAlpha(1); // 未选中项目的透明度 // 不包含spacing会导致onKeyDown()失效!!! 失效onKeyDown()前先调用onScroll(null,1,0)可处理 setSpacing(0); // 取靠近中间 图片数组的整倍数 setSelection((getCount() / 2 / listImgs.size()) * listImgs.size()); // 默认选中中间位置为起始位置 setFocusableInTouchMode(true); initOvalLayout();// 初始化圆点 startTimer();// 开始自动滚动任务 } /** 初始化图片组 */ private void ininImages() { listImgs = new ArrayList<ImageView>(); // 图片组 int len = list.size() != 0 ? list.size() : mAdsId.length; for (int i = 0; i < len; i++) { ImageView imageview = new ImageView(mContext); // 实例化ImageView的对象 imageview.setScaleType(ImageView.ScaleType.FIT_XY); // 设置缩放方式 imageview.setLayoutParams(new Gallery.LayoutParams( Gallery.LayoutParams.MATCH_PARENT, Gallery.LayoutParams.MATCH_PARENT)); if (list.size() == 0) {// 本地加载图片 imageview.setImageResource(mAdsId[i]); // 为ImageView设置要显示的图片 } else { // 网络加载图片 il = ImageLoader.getInstance(); il.init(ImageLoaderConfiguration.createDefault(mContext)); il.displayImage(list.get(i), imageview); } listImgs.add(imageview); } } /** 初始化圆点 */ private void initOvalLayout() { if (mOvalLayout != null && listImgs.size() < 2) {// 如果只有一第图时不显示圆点容器 mOvalLayout.removeAllViews(); mOvalLayout.getLayoutParams().height = 0; } else if (mOvalLayout != null) { mOvalLayout.removeAllViews(); // 圆点的大小是 圆点窗口的 70%; int Ovalheight = (int) (mOvalLayout.getLayoutParams().height * 0.7); // 圆点的左右外边距是 圆点窗口的 20%; int Ovalmargin = (int) (mOvalLayout.getLayoutParams().height * 0.2); android.widget.LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( Ovalheight, Ovalheight); layoutParams.setMargins(Ovalmargin, 0, Ovalmargin, 0); for (int i = 0; i < listImgs.size(); i++) { View v = new View(mContext); // 员点 v.setLayoutParams(layoutParams); v.setBackgroundResource(mNormalId); mOvalLayout.addView(v); } // 选中第一个 mOvalLayout.getChildAt(0).setBackgroundResource(mFocusedId); } } /** 无限循环适配器 */ class AdAdapter extends BaseAdapter { @Override public int getCount() { if (listImgs.size() < 2)// 如果只有一张图时不滚动 return listImgs.size(); return Integer.MAX_VALUE; } @Override public View getView(int position, View convertView, ViewGroup parent) { return listImgs.get(position % listImgs.size()); // 返回ImageView } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { int kEvent; if (isScrollingLeft(e1, e2)) { // 检查是否往左滑动 kEvent = KeyEvent.KEYCODE_DPAD_LEFT; } else { // 检查是否往右滑动 kEvent = KeyEvent.KEYCODE_DPAD_RIGHT; } onKeyDown(kEvent, null); return true; } /** 检查是否往左滑动 */ private boolean isScrollingLeft(MotionEvent e1, MotionEvent e2) { return e2.getX() > (e1.getX() + 50); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return super.onScroll(e1, e2, distanceX, distanceY); } @Override public boolean onTouch(View v, MotionEvent event) { if (MotionEvent.ACTION_UP == event.getAction() || MotionEvent.ACTION_CANCEL == event.getAction()) { startTimer();// 开始自动滚动任务 } else { stopTimer();// 停止自动滚动任务 } return false; } /** 图片切换事件 */ @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long arg3) { curIndex = position % listImgs.size(); if (mOvalLayout != null && listImgs.size() > 1) { // 切换圆点 mOvalLayout.getChildAt(oldIndex).setBackgroundResource(mNormalId); // 圆点取消 mOvalLayout.getChildAt(curIndex).setBackgroundResource(mFocusedId);// 圆点选中 oldIndex = curIndex; } // adgallerytxt.setText("" + curIndex); } @Override public void onNothingSelected(AdapterView<?> arg0) { } /** 项目点击事件 */ @Override public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { if (mMyOnItemClickListener != null) { mMyOnItemClickListener.onItemClick(curIndex); } } /** 设置项目点击事件监听器 */ public void setMyOnItemClickListener(MyOnItemClickListener listener) { mMyOnItemClickListener = listener; } /** 项目点击事件监听器接口 */ public interface MyOnItemClickListener { /** * @param curIndex * //当前条目在数组中的下标 */ void onItemClick(int curIndex); } /** 停止自动滚动任务 */ public void stopTimer() { if (mTimer != null) { mTimer.cancel(); mTimer = null; } } /** 开始自动滚动任务 图片大于1张才滚动 */ public void startTimer() { if (mTimer == null && listImgs.size() > 1 && mSwitchTime > 0) { mTimer = new Timer(); mTimer.schedule(new TimerTask() { public void run() { handler.sendMessage(handler.obtainMessage(1)); } }, mSwitchTime, mSwitchTime); } } /** 处理定时滚动任务 */ @SuppressLint("HandlerLeak") private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); // 不包含spacing会导致onKeyDown()失效!!! // 失效onKeyDown()前先调用onScroll(null,1,0)可处理 onScroll(null, null, 1, 0); onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, null); } };}
在此感谢MyPagerGalleryView控件的作者,让我们少做轮子~虽然我觉得造轮子是技术提升的一个重要手段。
4、Tab+Fragment+ViewPager的封装
未完待续……
曾经沧海难为水,除却巫山不是云。
- Android ViewPager使用小结
- Android ViewPager使用方法小结
- android 中viewPager小结
- Android ViewPager的架构小结
- (ViewPager)Android ViewPager使用详解
- Android ViewPager使用详解
- Android ViewPager 使用详解
- Android ViewPager使用详解
- Android ViewPager使用详解
- Android ViewPager使用详解
- Android ViewPager使用详解
- Android ViewPager使用详解
- Android ViewPager使用详解
- Android ViewPager使用详解
- Android ViewPager使用详解
- Android ViewPager使用详解
- ViewPager android 使用
- Android ViewPager使用详解
- StringTokenizer类的使用方法
- MFCC倒谱系数特征提取与识别
- Spring4下载f.txt文件解决方法
- 继续指针
- android中handler,message,message queue,looper底层实现机制
- Android ViewPager使用小结
- Linux下MySQL数据库常用基本操作
- Errors occurred during the build. Errors running builder 'DeploymentBuilder' on project 'myf'. java.
- CDatabase类
- 百度离线地图服务器搭建
- sqlserver---删除表数据drop、truncate和delete的用法
- HTML中设置input等文本框为不可操作
- HDU 5904 LCIS __ dp、LCIS
- 硬盘接口查看