一、前言
在日常開發中, 幾乎每一個項目都會使用到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佈局文件,主要是太簡單。 也不想讓學習者看太多的代碼, 怕你們會覺得煩。
基本的邏輯都是比較清晰的, 也非常的容易懂。 (不喜請噴!!!)