- 什么是ViewPager和ViewPager使用场景
ViewPage是v4扩展包中提供的一个控件。是一个ViewGroup,可以包含很多的View,当手指在屏幕上左右滑动的时候,可以切换页面。ViewPager一般与Fragment结合使用比较方便。
大家经常见到的app的引导界面通常会用到ViewPager技术。
- 使用ViewPager
ViewPager的使用,与ListView使用类似,也需要绑定相应的适配器。
ViewPager 使用主要分3个步骤:
- 在布局文件中添加ViewPager控件。注意:写这个控件的时候要写全称(包名+类名)
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
2.加载要显示的页面,并把要显示的页面放入数组或List 集合中。
LayoutInflater lf = getLayoutInflater().from(this);
view1 = lf.inflate(R.layout.layout1, null);
view2 = lf.inflate(R.layout.layout2, null);
view3 = lf.inflate(R.layout.layout3, null);
viewList = new ArrayList<View>();
viewList.add(view1);
viewList.add(view2);
viewList.add(view3);
3.在Activity里实例化ViewPager组件,并设置它的Adapter,一般需要重写PagerAdapter。
(和ListView使用方式差不多,使用步骤也类似。)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection_demo);
// ViewPager and its adapters use support library
// fragments, so use getSupportFragmentManager.
mDemoCollectionPagerAdapter =
new DemoCollectionPagerAdapter(
getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
}
ViewPager的方法:----了解
- setAdapter():ViewPager 通过 setAdapter() 来建立与 PagerAdapter 的联系。这个联系是双向的,一方面,ViewPager 会拥有 PagerAdapter 对象,从而可以在需要时调用 PagerAdapter 的方法;另一方面,ViewPager 会在 setAdapter() 中调用 PagerAdapter 的 registerDataSetObserver() 方法,注册一个自己生成的 PagerObserver 对象,从而在 PagerAdapter 有所需要时(如 notifyDataSetChanged() 或 notifyDataSetInvalidated() 时),可以调用 Observer 的 onChanged() 或 onInvalidated() 方法,从而实现 PagerAdapter 向 ViewPager 方向发送信息。
-
dataSetChanged():在 PagerObserver.onChanged(),以及 PagerObserver.onInvalide() 中被调用。因此当 PagerAdapter.notifyDataSetChanged() 被触发时,ViewPager.dataSetChanged() 也可以被触发。该函数将使用 getItemPosition() 的返回值来进行判断,如果为 POSITION_UNCHANGED,则什么都不做;如果为 POSITION_NONE,则调用 PagerAdapter.destroyItem() 来去掉该对象,并设置为需要刷新 (needPopulate = true) 以便触发 PagerAdapter.instantiateItem() 来生成新的对象。
- PageAdapter
PageAdapter 是 ViewPager 的支持者,ViewPager 将调用它来取得所需显示的页,而 PageAdapter 也会在数据变化时,通知 ViewPager。这个类也是FragmentPagerAdapter 以及 FragmentStatePagerAdapter 的基类。如果继承该类,至少需要实现 instantiateItem(), destroyItem(), getCount() 以及 isViewFromObject()四个方法。
- nstantiateItem():在每次 ViewPager 需要一个用以显示的 Object 的时候,该方法都会被 ViewPager.addNewItem()方法 调用。该方法内部一定要把指定位置要显示的视图添加到ViewPager中。
- destroyItem():从当前的ViewPager容器中删除指定位置的View对象。
- getCount ():返回要滑动的View的个数。
- isViewFromObject():该方法用来判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图(即它俩是否是对应的,对应的表示同一个View) 返回值:如果对应的是同一个View,返回True,否则返回False。
- ViewPager添加标题
- 给ViewPager添加一个子标签
<android.support.v4.view.PagerTitleStrip
android:id="@+id/pagertitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top" />
注意:android:layout_gravity="top" 属性的值有top和bottom,表示把title放在ViewPager的顶部还是底部
- 覆写PageAdapter的getPageTitle(position)方法,该方法返回每个页面的title。
@Override
public CharSequence getPageTitle(int position) {
}
pagerTabStrip.setTabIndicatorColor(getResources().getColor(R.color.gold));//设置指示器的颜色
pagerTabStrip.setBackgroundColor(getResources().getColor(R.color.azure)); //设置标题背景色
pagerTabStrip.setTextSpacing(50);//设置间距无效,不知道为什么。
注意:还有一种标题是android.support.v4.view.PagerTabStrip用法与上面的完全一样,唯一区别就是每个标题下面添加了一个下划线,并且标题也可点击
- 给ViewPager添加监听器OnPageChangeListener
pager.setOnPageChangeListener(new OnPageChangeListener() {
/**
* 当滑动结束后,新的pager完全显示到屏幕后会调用该方法
* 参数:新的pager的index
*/
@Override
public void onPageSelected(int arg0) {
// Log.e(TAG, "onPageSelected..." + arg0);
}
/**
* 当正在滑动时,会一直回调该方法
* arg0 :当前页面,及你点击滑动的页面
* arg1:当前页面偏移的百分比
* arg2:当前页面偏移的像素位置
*/
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// Log.e(TAG, "onPageScrolled..." + arg0 + " " + arg1 + " " + arg2);
}
/**
* 当状态方法改变的时候调用
* 参数:页面的状态
* 共有三种状态:
* SCROLL_STATE_IDLE 页面静止的时候的状态
SCROLL_STATE_DRAGGING 正在滑动的状态
SCROLL_STATE_SETTLING 到了要滑动的最终位置的状态
*/
@Override
public void onPageScrollStateChanged(int arg0) {
//
Log.e(TAG, "onPageScrollStateChanged..." + msg);
if (state == ViewPager.SCROLL_STATE_DRAGGING
&& viewPager.getCurrentItem()==viewPager.getChildCount() )
//判断是否是最后一页
}
});
动态创建radiobutton
RadioButton radioButton = new RadioButton(MainActivity.this);
radioButton.setId(i);
radioGroup.addView(radioButton);
动态设置radiobutton选中:
((RadioButton)radioGroup.getChildAt(0)).setChecked(true);
扩展:实现首次运行软件的闪屏页面
- 欢迎页---停留2秒
- 判断是否是第一次运行软件
- 是的话 进入广告页(3-4张图片 能够指示位置,用小圆点图 用户滑动到最后一页进入主界面)
- 不是第一次运行 直接进入主界面
设置activity全屏
首先设置主题为Theme.AppCompat.Light.NoActionBar
增加<item name="android:windowFullscreen">true</item>
//在按下返回键的时候会回调
public void onBackPressed() {
if (isFirst) {
Toast.makeText(this, "再按一次退出", 0).show();
lastTime = System.currentTimeMillis();
isFirst = false;
} else {
long currentTime = System.currentTimeMillis();
if (currentTime - lastTime <= 2000) {
finish();
} else {
Toast.makeText(this, "再按一次退出", 0).show();
lastTime = System.currentTimeMillis();
}
}
}
- FragmentPagerAdapter的使用
FragmentPagerAdapter是PagerAdapter的其中一种实现。它将每一个页面表示为一个 Fragment,并且每一个Fragment都将会保存到fragmentManager当中。而且,当用户没可能再次回到页面的时候,fragmentManager才会将这个Fragment销毁。
让Fragment 成为ViewPager的一页时,FragmentManager会一直保存管理创建好了的Fragment,即使当前不是显示的这一页,Fragment对象也不会被销毁,在后台默默等待重新显示。但如果Fragment不再可见时,它的视图层次会被销毁掉,下次显示时视图会重新创建。
这种pager十分适用于有一些静态fragment,例如一组tabs的时候使用。每个页面对应的Fragment当用户可以访问的时候会一直存在内存中。
使用FragmentPagerAdapter至少需要实现以下两个方法:
FragmentPagerAdapter adapter = new FragmentPagerAdapter(
getSupportFragmentManager()) {
//返回ViewPager页面的数量
@Override
public int getCount() {
return fragments.size();
}
//要显示的fragent对象。
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
}
};
- 补充 自定义viewPager的Tab导航标签
- 分析标签的结构
<?xml version="1.0" encoding="utf-8"?>
<!-- tab控件的布局 -->
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/hsv_id"
android:scrollbars="@null"
>
<!-- 最外层的LinearLayout 纵向 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Tab项布局 横向 -->
<LinearLayout
android:id="@+id/ll_tab"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="9"
android:orientation="horizontal"/>
<View
android:id="@+id/view_nav"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#f00"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#f00"/>
</LinearLayout>
</HorizontalScrollView>
- 测量每一个标签的宽度
tv.getPaint().setFakeBoldText(true);//设置字体加粗效果
//调用一下组件的测量方法
tv.measure(0, 0);//通知系统对组件进行测量
tv.getMeasuredWidth();//获得标签的宽度
- 移动滑块的位置
//计算滑块的宽度
if (position == titleWidths.size()-1){
slideWidth = titleWidths.get(position);
}else {
slideWidth =(int)(titleWidths.get(position)+
(titleWidths.get(position+1)-titleWidths.get(position))
*positionOffset);
}
//滑块位置
int slideMarginLeft = 0;
for (int i = 0; i < position; i++)
{
slideMarginLeft += titleWidths.get(i);
}
slideMarginLeft+=titleWidths.get(position)*positionOffset;
slidePrams.leftMargin = slideMarginLeft;
- 补充 FragmentPagerAdapter 和 FragmentStatePagerAdapter 的区别:
FragmentPagerAdapter:只会销毁fragment的视图,fragment的对象被保留在了内存中,下次再创建该fragment时,直接从内存中获得该对象,如果页面较少,
并且不需要动态更新时,用这种适配器用户体验较好,开销较少
FragmentStatePagerAdapter:会直接销毁fragment对象,下次再使用该fragment时,重新创建新的对象。页面较多,并且需要动态更新的时候,需要使用该适配器。