Android ViewPager 实现 TabHost 的效果
经过了前三个范例,我几乎对使用 Android 实现 今日头条 滑动效果失去了耐心了,决定自己定制一个了
不过, ViewPager
本身的功能是非常棒的,我们要定制的也就是 PagerTabStrip
,姑且,我们称之为 MsPagerTabStrip
吧
MsPagerStrip
我们先来看看 MsPagerStrip
长的啥样
布局
我们可以把布局分为两大块
- 标题栏,有多少个滑动页面就有多少个
TextView
,且标题栏不会动 - 下划线指示器,有一个背景色,然后是一个
View
会随着滑动而滑动
对于这种布局,我们最喜欢使用的就是 LinearLayout
- 顶部一个
LinearLayout
,包着三个TextView
,weight
属性都为1
- 下面跟着一个导轨
View
和一个滑块的View
-
最底下是
ViewPager
,我们会使用到它的两个属性android:flipInterval
指定 View 动画间的时间间隔的persistentDrawingCache
设置控件的绘制缓存策略
可选值有四个,可以同时用多个,多个之间用
|
分割值 说明 none 不在内存中保存绘图缓存 animation 只保存动画绘图缓存 scrolling 只保存滚动效果绘图缓存 all 所有的绘图缓存都应该保存在内存中
动画
布局讲完了,我们就来看看动画
滑动的时候,滑块会从指定位置滑到下一个位置
-
首先我们需要将整个滑动区域分成
N
段,每一段的长度等于 屏幕总宽度 / n因为我们只有三个页面,所以有 n=3
-
确定滑块的宽度,刚好也等于 屏幕总宽度 / n
-
确定每次滑动移动的距离,其实算起来,也等于自身的宽度,只是有正有负 length
-
因为我们使用的是
TranslateAnimation
动画,它很简单,只要我们传递起始坐标和终点坐标即可 -
我们的滑动都是水平滑动,所以 y 轴的坐标可以忽略
-
动画的坐标系都是以 View 的左上角为起始点的
-
所以要确定当前的 x 坐标就只需要 (index * length) 即可 ( index 从 0 开始)
-
终点的 x 坐标也很简单还是 (index * length) ,这个你可以通过代码来看更容易
-
确定每次移动的时间,其实等于
ViewPager
切换页面的时间
实现
经过上面的分析,我们就可以开始实现了
动画方面,因为我们还没学到,所以你可以直接忽略,或者后面再回来看看
-
复用 Android ViewPager 页面切换组件 3 中的 demo
-
修改
activity_main.xml
添加整体的布局<?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="44dp" android:background="#FFFFFF"> <TextView android:id="@+id/title_one" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" android:gravity="center" android:text="科技" android:textColor="#000000" /> <TextView android:id="@+id/title_two" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" android:gravity="center" android:text="电影" android:textColor="#000000" /> <TextView android:id="@+id/title_three" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1.0" android:gravity="center" android:text="小说" android:textColor="#000000" /> </LinearLayout> <RelativeLayout android:layout_width="match_parent" android:background="#dddddd" android:layout_height="4dp" > <View android:id="@+id/slider" android:background="#333333" android:layout_width="32dp" android:layout_height="fill_parent" /> </RelativeLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="wrap_content" android:layout_height="0dp" android:layout_gravity="center" android:layout_weight="1.0" android:flipInterval="30" android:persistentDrawingCache="animation" /> </LinearLayout>
-
修改
MsPagerAdapter.java
package cn.twle.android.viewpager; import android.support.v4.view.PagerAdapter; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; public class MsPagerAdapter extends PagerAdapter { private ArrayList<View> mData; public MsPagerAdapter() { } public MsPagerAdapter(ArrayList<View> view_list) { super(); this.mData = view_list; } @Override public int getCount() { return mData.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(mData.get(position)); return mData.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(mData.get(position)); } }
-
修改
MainActivity.java
package cn.twle.android.viewpager; import android.graphics.Matrix; import android.os.Bundle; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; import android.view.animation.Animation; import android.view.animation.TranslateAnimation; import android.widget.TextView; import java.util.ArrayList; public class MainActivity extends AppCompatActivity implements View.OnClickListener, ViewPager.OnPageChangeListener { private ViewPager viewpager; private View slider; private TextView title_one; private TextView title_two; private TextView title_three; private ArrayList<View> listViews; private int offset = 0;//移动条图片的偏移量 private int currIndex = 0;//当前页面的编号 private int bmpWidth;// 移动条图片的长度 private int one = 0; //移动条滑动一页的距离 private int two = 0; //滑动条移动两页的距离 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewpager = (ViewPager) findViewById(R.id.viewpager); title_one = (TextView) findViewById(R.id.title_one); title_two = (TextView) findViewById(R.id.title_two); title_three = (TextView) findViewById(R.id.title_three); slider = (View) findViewById(R.id.slider); //下划线动画的相关设置 -- start // 屏幕相关 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); int screenW = dm.widthPixels;// 获取分辨率宽度 bmpWidth = screenW / 3; // 获取滑块应该的宽度 // 设置滑块宽度 slider.getLayoutParams().width = bmpWidth; // 计算初始滑块偏移量 offset = (screenW / 3 - bmpWidth) / 2;// 计算偏移量 Matrix matrix = new Matrix(); matrix.postTranslate(offset, 0); //移动的距离 one = offset * 2 + bmpWidth;// 移动一页的偏移量,比如1->2,或者2->3 two = one * 2;// 移动两页的偏移量,比如1直接跳3 // 往 ViewPager 填充 View,同时设置点击事件与页面切换事件 listViews = new ArrayList<View>(); LayoutInflater mInflater = getLayoutInflater(); listViews.add(mInflater.inflate(R.layout.view_one, null, false)); listViews.add(mInflater.inflate(R.layout.view_two, null, false)); listViews.add(mInflater.inflate(R.layout.view_three, null, false)); viewpager.setAdapter(new MsPagerAdapter(listViews)); viewpager.setCurrentItem(0); //设置ViewPager当前页,从0开始算 title_one.setOnClickListener(this); title_two.setOnClickListener(this); title_three.setOnClickListener(this); viewpager.addOnPageChangeListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.title_one: viewpager.setCurrentItem(0); break; case R.id.title_two: viewpager.setCurrentItem(1); break; case R.id.title_three: viewpager.setCurrentItem(2); break; } } @Override public void onPageSelected(int index) { int fromX = currIndex * bmpWidth; int toX = index * bmpWidth; Animation animation = new TranslateAnimation(fromX, toX, 0, 0); currIndex = index; animation.setFillAfter(true);// true表示图片停在动画结束位置 animation.setDuration(300); //设置动画时间为300毫秒 slider.startAnimation(animation);//开始动画 } @Override public void onPageScrollStateChanged(int i) { } @Override public void onPageScrolled(int i, float v, int i1) { } }