当前位置: 移动技术网 > IT编程>移动开发>Android > Android中ViewPager实现滑动指示条及与Fragment的配合

Android中ViewPager实现滑动指示条及与Fragment的配合

2019年07月24日  | 移动技术网IT编程  | 我要评论

80后少林方丈txt下载,爱妃是只九尾猫,最新邮票行情

自主实现滑动指示条
先上效果图:

2016323115400211.png (300×500)2016323115431597.png (300×500)

1、xml布局
布局代码如下:

<linearlayout 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:orientation="vertical" 
 tools:context="com.example.testviewpage_2.mainactivity" > 
  
  <imageview 
  android:id="@+id/cursor" 
  android:layout_width="fill_parent" 
  android:layout_height="wrap_content" 
  android:scaletype="matrix" 
  android:src="@drawable/a" /> 
 
 <android.support.v4.view.viewpager 
  android:id="@+id/viewpager" 
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content" 
  android:layout_gravity="center"/> 
 
</linearlayout> 

采用线性垂直布局,在滑动页面的上方添加一个小水平条。

2、java代码
先给出全部代码,然后再逐步讲解。

public class mainactivity extends activity { 
 
 private view view1, view2, view3; 
 private list<view> viewlist;// view数组 
 private viewpager viewpager; // 对应的viewpager 
 
 private imageview cursor; 
 private int bmpw = 0; // 游标宽度 
 private int offset = 0;// // 动画图片偏移量 
 private int currindex = 0;// 当前页卡编号 
 
 @override 
 protected void oncreate(bundle savedinstancestate) { 
  super.oncreate(savedinstancestate); 
  setcontentview(r.layout.activity_main); 
 
  viewpager = (viewpager) findviewbyid(r.id.viewpager); 
  layoutinflater inflater = getlayoutinflater(); 
  view1 = inflater.inflate(r.layout.layout1, null); 
  view2 = inflater.inflate(r.layout.layout2, null); 
  view3 = inflater.inflate(r.layout.layout3, null); 
 
  viewlist = new arraylist<view>();// 将要分页显示的view装入数组中 
  viewlist.add(view1); 
  viewlist.add(view2); 
  viewlist.add(view3); 
 
  //初始化指示器位置 
  initcursorpos(); 
   
  viewpager.setadapter(new mypageradapter(viewlist)); 
  viewpager.setonpagechangelistener(new mypagechangelistener()); 
 
 } 
  
 //初始化指示器位置 
 public void initcursorpos() { 
  // 初始化动画 
  cursor = (imageview) findviewbyid(r.id.cursor); 
  bmpw = bitmapfactory.decoderesource(getresources(), r.drawable.a) 
    .getwidth();// 获取图片宽度 
 
  displaymetrics dm = new displaymetrics(); 
  getwindowmanager().getdefaultdisplay().getmetrics(dm); 
  int screenw = dm.widthpixels;// 获取分辨率宽度 
  offset = (screenw / viewlist.size() - bmpw) / 2;// 计算偏移量 
 
  matrix matrix = new matrix(); 
  matrix.posttranslate(offset, 0); 
  cursor.setimagematrix(matrix);// 设置动画初始位置 
 } 
  
 
 //页面改变监听器 
 public class mypagechangelistener implements onpagechangelistener { 
 
  int one = offset * 2 + bmpw;// 页卡1 -> 页卡2 偏移量 
  int two = one * 2;// 页卡1 -> 页卡3 偏移量 
 
  @override 
  public void onpageselected(int arg0) { 
   animation animation = null; 
   switch (arg0) { 
   case 0: 
    if (currindex == 1) { 
     animation = new translateanimation(one, 0, 0, 0); 
    } else if (currindex == 2) { 
     animation = new translateanimation(two, 0, 0, 0); 
    } 
    break; 
   case 1: 
    if (currindex == 0) { 
     animation = new translateanimation(offset, one, 0, 0); 
    } else if (currindex == 2) { 
     animation = new translateanimation(two, one, 0, 0); 
    } 
    break; 
   case 2: 
    if (currindex == 0) { 
     animation = new translateanimation(offset, two, 0, 0); 
    } else if (currindex == 1) { 
     animation = new translateanimation(one, two, 0, 0); 
    } 
    break; 
   } 
   currindex = arg0; 
   animation.setfillafter(true);// true:图片停在动画结束位置 
   animation.setduration(300); 
   cursor.startanimation(animation); 
  } 
 
  @override 
  public void onpagescrolled(int arg0, float arg1, int arg2) { 
  } 
 
  @override 
  public void onpagescrollstatechanged(int arg0) { 
  } 
 } 
 
 /** 
  * viewpager适配器 
  */ 
 public class mypageradapter extends pageradapter { 
  public list<view> mlistviews; 
 
  public mypageradapter(list<view> mlistviews) { 
   this.mlistviews = mlistviews; 
  } 
 
  @override 
  public boolean isviewfromobject(view arg0, object arg1) { 
   // todo auto-generated method stub 
   return arg0 == arg1; 
  } 
 
  @override 
  public int getcount() { 
   // todo auto-generated method stub 
   return mlistviews.size(); 
  } 
 
  @override 
  public void destroyitem(viewgroup container, int position, object object) { 
   // todo auto-generated method stub 
   container.removeview(mlistviews.get(position)); 
  } 
 
  @override 
  public object instantiateitem(viewgroup container, int position) { 
   // todo auto-generated method stub 
   container.addview(mlistviews.get(position)); 
 
   return mlistviews.get(position); 
  } 
 } 
 
} 

从易到难一步步来讲。
1、mypageradapter类

一般我们对于适配器的实现总是new一个pageadapter的实例。我们这里做了一点稍微的更改,将其集合成一个类,内容都没变,只是多了一个构造函数而已。所以针对这个类的具体代码,我就不再细讲,如果对其中的复写的函数为什么要这么写不理解的同学,请看《viewpager 详解(二)---详解四大函数》

2、initcursorpos()---初始化指示器位置
游标在初始化显示时,我们要根据屏幕宽度来显示游标位置。先看看这部分代码:

//初始化指示器位置 
public void initcursorpos() { 
 // 初始化动画 
 cursor = (imageview) findviewbyid(r.id.cursor); 
 bmpw = bitmapfactory.decoderesource(getresources(), r.drawable.a) 
   .getwidth();// 获取图片宽度 
 
 displaymetrics dm = new displaymetrics(); 
 getwindowmanager().getdefaultdisplay().getmetrics(dm); 
 int screenw = dm.widthpixels;// 获取分辨率宽度 
 offset = (screenw / viewlist.size() - bmpw) / 2;// 计算偏移量 
 
 matrix matrix = new matrix(); 
 matrix.posttranslate(offset, 0); 
 cursor.setimagematrix(matrix);// 设置动画初始位置 
} 

可能有些同学不明白的位置在于,初始化位置的偏移量为什么这么算,下面,我画了张图,看下就应该明白了。

2016323115509630.png (960×540)

最后对于偏移的方法,可用的很多,这里仿网上的代码用了matrix;当然大家可以用其它的偏移方法,一样。

3、mypagechangelistener()---页面改变监听器
代码如下 :

public class mypagechangelistener implements onpagechangelistener { 
 
 int one = offset * 2 + bmpw;// 页卡1 -> 页卡2 偏移量 
 int two = one * 2;// 页卡1 -> 页卡3 偏移量 
 
 @override 
 public void onpageselected(int arg0) { 
  animation animation = null; 
  switch (arg0) { 
  case 0: 
   if (currindex == 1) { 
    animation = new translateanimation(one, 0, 0, 0); 
   } else if (currindex == 2) { 
    animation = new translateanimation(two, 0, 0, 0); 
   } 
   break; 
  case 1: 
   if (currindex == 0) { 
    animation = new translateanimation(offset, one, 0, 0); 
   } else if (currindex == 2) { 
    animation = new translateanimation(two, one, 0, 0); 
   } 
   break; 
  case 2: 
   if (currindex == 0) { 
    animation = new translateanimation(offset, two, 0, 0); 
   } else if (currindex == 1) { 
    animation = new translateanimation(one, two, 0, 0); 
   } 
   break; 
  } 
  currindex = arg0; 
  animation.setfillafter(true);// true:图片停在动画结束位置 
  animation.setduration(300); 
  cursor.startanimation(animation); 
 } 

原理是这样,根据滑动到的页面,把游标滑动找指定位置。
这里可能有难度的地方在于,数学……
我画了一张图,解释从第一个页面到第二个页面时的距离为什么是“游标宽度+offset*2”,其它距离类似。

2016323115543616.png (960×540)

这篇就到这了,而且这个难度不太大,讲的可能不太细。
源码中,给大家列出了一个有tab交互的demo,图片如下:

2016323115611176.png (300×533)2016323115625900.png (300×533)

使用fragment实现viewpager滑动
使用fragment实现viewpager滑动是android官方比较推荐的一种做法,我们先再来看一下效果图:
在第一个页面加一个btn

2016323115641975.png (300×533)

第一页面向第二页面滑动

2016323115656400.png (300×533)

第二页面向第三个页面滑动

2016323115713962.png (300×533)

1、适配器实现——fragmentpageradapter
先看完整代码,再细讲:

public class fragadapter extends fragmentpageradapter { 
 
 private list<fragment> mfragments; 
  
 public fragadapter(fragmentmanager fm,list<fragment> fragments) { 
  super(fm); 
  // todo auto-generated constructor stub 
  mfragments=fragments; 
 } 
 
 @override 
 public fragment getitem(int arg0) { 
  // todo auto-generated method stub 
  return mfragments.get(arg0); 
 } 
 
 @override 
 public int getcount() { 
  // todo auto-generated method stub 
  return mfragments.size(); 
 } 
 
} 

这里有三个函数,根据第一部分的官方文档,可知,对于fragmentpageradapter的派生类,只重写getitem(int)和getcount()就可以了。
对于构造函数,这里申请了一个fragment的list对象,用于保存用于滑动的fragment对象,并在创造函数中初始化:

public fragadapter(fragmentmanager fm,list<fragment> fragments) { 
 super(fm); 
 // todo auto-generated constructor stub 
 mfragments=fragments; 
} 

然后在getitem(int arg0)中,根据传来的参数arg0,来返回当前要显示的fragment,下面是getitem的官方解释,难度不大,不再细讲。
public abstract fragment getitem (int position)

return the fragment associated with a specified position.

最后,getcount()返回用于滑动的fragment总数;

从构造函数所以看出,我们要构造fragment的集合才行,所以下面我们就先产生我们所需要的fragment类;
2、三个fragment类
第一个fragment类:
xml:(layout1.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:background="#ffffff" 
 android:orientation="vertical" > 
  
 <button android:id="@+id/fragment1_btn" 
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content" 
  android:text="show toast" 
  /> 
</linearlayout> 

在其中加入了一个btn

java代码:

public class fragment1 extends fragment { 
  
 @override 
 public view oncreateview(layoutinflater inflater, viewgroup container, 
   bundle savedinstancestate) { 
  // todo auto-generated method stub 
  view view= inflater.inflate(r.layout.layout1, container, false); 
   
  //对view中控件的操作方法 
  button btn = (button)view.findviewbyid(r.id.fragment1_btn); 
  btn.setonclicklistener(new view.onclicklistener() { 
    
   @override 
   public void onclick(view v) { 
    // todo auto-generated method stub 
    toast.maketext(getactivity(), "点击了第一个fragment的btn", toast.length_short).show(); 
   } 
  }); 
  return view; 
 } 
} 

在oncreateview()中返回要显示的view,上面这段代码简单演示了如何对视图里的控件进行操作,难度不大,不再细讲。第二个fragment类:

xml代码:(layout2.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:background="#ffff00" 
 android:orientation="vertical" > 
  
 
</linearlayout> 

java代码:

public class fragment2 extends fragment { 
  
 @override 
 public view oncreateview(layoutinflater inflater, viewgroup container, 
   bundle savedinstancestate) { 
  // todo auto-generated method stub 
  view view=inflater.inflate(r.layout.layout2, container, false); 
  return view; 
 } 
 
} 

第三个fragment类:
xml代码:(layout3.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:background="#ff00ff" 
 android:orientation="vertical" > 
  
 
</linearlayout> 

java代码:

public class fragment3 extends fragment { 
  
 @override 
 public view oncreateview(layoutinflater inflater, viewgroup container, 
   bundle savedinstancestate) { 
  // todo auto-generated method stub 
  view view=inflater.inflate(r.layout.layout3, container, false); 
  return view; 
 } 
 
} 

3、主activity实现
核心代码:

public class mainactivity extends fragmentactivity { 
 
 @override 
 protected void oncreate(bundle savedinstancestate) { 
  super.oncreate(savedinstancestate); 
  setcontentview(r.layout.activity_main); 
 
  //构造适配器 
  list<fragment> fragments=new arraylist<fragment>(); 
  fragments.add(new fragment1()); 
  fragments.add(new fragment2()); 
  fragments.add(new fragment3()); 
  fragadapter adapter = new fragadapter(getsupportfragmentmanager(), fragments); 
   
  //设定适配器 
  viewpager vp = (viewpager)findviewbyid(r.id.viewpager); 
  vp.setadapter(adapter); 
 } 
 
} 

首先有一个最值得注意的地方:activity派生自fragmentactivity,其实这是有关fragment的基础知识,只有fragmentactivity才能内嵌fragment页面,普通activity是不行的。

这段代码主要分为两步,第一步:构造适配器;第二步:设定适配器。
先看构造适配器的过程:

//构造适配器 
list<fragment> fragments=new arraylist<fragment>(); 
fragments.add(new fragment1()); 
fragments.add(new fragment2()); 
fragments.add(new fragment3()); 
fragadapter adapter = new fragadapter(getsupportfragmentmanager(), fragments); 

构造一个fragment列表,然后将上面的三个fragment类对应的实例添加进去,最后生成fragadapter实例。
至于第二步,设定适配器,没什么好讲的。
4、可能出现的问题
问题:在mainactivity中,当写到这句:fragments.add(new fragment1()); 向fragment列表中添加fragement对象实例时,会提示“无法将fragment1()转换为fragment”

解决办法 :这是因为导入包不一致,一般的问题在于:在fragment1中导入的是android.app.fragment, 而在这里导入类确是:android.support.v4.app.fragment,包不同当然无法转换,统一导入为android.support.v4.app.fragment之后就正常了
 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网