一、前言
在日常开发中, 几乎每一个项目都会使用到ViewPager这样的分页滚动控件。 但如果是用来Tab框架提示。
我也查看过很多这方面的博客, 发现关于计算这个提示线的代码都太复杂且代码很多, 很多不需要的代码。 这篇博客主要就是想要简化大部分代码来让学习者们更加的掌握住这方面的知识。
那么就需要一个较为友好的界面提示。 首先看一下我们的预览界面:
可以看出我们Tab的导航条处, 有一个红色的线一直在指引着我们的页面内容, 这就是所谓的界面提示。
二、动手动脑做起来
下面是项目结构:
关于我们的Fragment的话,我们ViewPager的Adapter采用了FragmentPagerAdapter的实现Tab方式。
Fragment类就不贴出代码了, 比较简单。 主要讲解一下,MainActivity.class+MyFragmentPagerAdapter.class类 ;
MyFragmentPagerAdapter.class:
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
private Fragment[] framgnets ;
public MyFragmentPagerAdapter(FragmentManager fm, Fragment[] f) {
super(fm);
// TODO Auto-generated constructor stub
this.framgnets = f ;
}
@Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return framgnets[arg0];
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return framgnets.length;
}
}
fragments: 就是用来接收ViewPager的各个Pager页面。 每个Fragment对应一个页面。
通常我们如果是继承于FragmentPagerAdapter的话, 就只需要重写getItem(int position)+ getCount(); 两个方法即可。
MainActivity.class:
import com.example.zxc_viewpager_scroll.fragment.FragmentPager1;
import com.example.zxc_viewpager_scroll.fragment.FragmentPager2;
import com.example.zxc_viewpager_scroll.fragment.FragmentPager3;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.widget.LinearLayout.LayoutParams;
public class MainActivity extends FragmentActivity {
private View mViewLine ;
private ViewPager mViewPager ;
private MyFragmentPagerAdapter mPagerAdapter ;
private Fragment[] fragments = null ;
private int width ;
private int pageCount = 3 ;
private Display mDisplay ;
private LayoutParams params;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findView() ;
fragments = new Fragment[3] ;
fragments[0] = new FragmentPager1() ;
fragments[1] = new FragmentPager2() ;
fragments[2] = new FragmentPager3() ;
mPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments) ;
mViewPager.setAdapter(mPagerAdapter);
mDisplay = getWindow().getWindowManager().getDefaultDisplay() ;
DisplayMetrics outMetrics = new DisplayMetrics() ;
mDisplay.getMetrics(outMetrics);
width = outMetrics.widthPixels / 3 ;
params = (LayoutParams) mViewLine.getLayoutParams();
params.width = width ;
mViewLine.setLayoutParams(params);
setListener() ;
}
private void findView(){
mViewLine = (View) findViewById(R.id.main_view_line) ;
mViewPager = (ViewPager) findViewById(R.id.main_viewpager) ;
}
private void setListener(){
mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
if(positionOffset != 0 && positionOffsetPixels != 0 ){
params.leftMargin = positionOffsetPixels / pageCount + width * position ;
mViewLine.setLayoutParams(params);
Log.i("TAG", position+" ; "+positionOffset+" ; "+positionOffsetPixels) ;
}
}
@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
});
}
}
这个类的代码就稍微有些长, 但是主要的处理逻辑是在onPageChangListener的监听方法中。 其他的也仅仅只是操作ViewPager的代码。
现在来分析一下。
看到width这个变量, 是用来控制红色线条的宽度,与Display、LayoutParams 配合使用。
pageCount主要是用来计算当前滑动的时候, 线条的左右边距。
解题思路: 主要操作其实就是那条红色的提示线。 当我们在滚动ViewPager的 时候, 只需要能够动态的操作提示线的左边距属性MarginLeft即可。
所以我们需要对ViewPager提供滚动的监听器, 其主要操作的方法就是public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
理解属性:
position,当前选中的页面位置(从0开始);
positionOffset, 大小从0到屏幕宽度或从屏幕宽度到0。 取决于你的左右滑动状态。
positionOffsetPixels, 主要就是对我们手指状态的一个操作。 值为1的时候, 正在滑动、 2: 手指擡起, 0: 结束了。
开始进入算法逻辑:
在我们的onPageScrolled中的处理, 首先我们需要保证当前的ViewPager处于可滑动状态。 否则就不要进行逻辑处理了,不然消费太大。
然后我们已经提前获取到了提示线的LayoutParams对象(不要在该方法啊中获取LayoutParams, 不然非常浪费内存) 。
params.leftMargin = positionOffsetPixels / pageCount + width * position ; 可以看出我们一直在不停的给MarginLeft计算值
然后mViewLine.stLayoutParams(params);不停的进行绘制, 这样可以有一种类似于动画的效果体现。
计算:positionOffsetPixels / pageCount: 我们有三个页面, 这样计算可以正常的分配每个Tab占有的屏幕宽度值;
width * position : width为提示线宽度, 这个值基本上就不需改变了。 position前面解释过意思了。 这样可以计算出我的当前MarginLeft的所需宽度大小。 (之后一直setLayoutParams就可以了。)
没有贴出xml布局文件,主要是太简单。 也不想让学习者看太多的代码, 怕你们会觉得烦。
基本的逻辑都是比较清晰的, 也非常的容易懂。 (不喜请喷!!!)