更新时间:2016-04-11
AppIntro 是一个引导页,就是我们平时启动应用时一闪而过的广告,当然以下内容和广告没什么关系,实现过程并不复杂,但不得不说作者的配图
以及配色
使得看上去确实很 cool
总的来说可以分成两个部分
Fragments 放在一个 List<Fragment>
中,每次根据 CurrentItem(当前页号)展现相应的 Fragment,相应的指示器中的圆点设为白色点。
init()
、
onSkipPressed()
、onDonePressed()
、onSlideChanged()
、onNextPressed()
在 onCreate
里绑定 Adapter,设置 OnPageChangeListenerfinal protected void onCreate(Bundle savedInstanceState) {
//...
requestWindowFeature(Window.FEATURE_NO_TITLE);
mPagerAdapter = new PagerAdapter(getSupportFragmentManager(), fragments);
pager = (AppIntroViewPager) findViewById(R.id.view_pager);
pager.setAdapter(this.mPagerAdapter);
pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
if (slidesNumber > 1) {
mController.selectPosition(position);
}
// 通过滑动上一页可重新启用向右滑动
if (!pager.isNextPagingEnabled()) {
if (pager.getCurrentItem() != pager.getLockPage()) {
setProgressButtonEnabled(baseProgressButtonEnabled);
pager.setNextPagingEnabled(true);
} else {
setProgressButtonEnabled(progressButtonEnabled);
}
} else {
setProgressButtonEnabled(progressButtonEnabled);
}
setButtonState(skipButton, skipButtonEnabled);
onSlideChanged();
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
//...
}
设置底部按钮的显示/隐藏
public void setProgressButtonEnabled(boolean progressButtonEnabled) {
this.progressButtonEnabled = progressButtonEnabled;
if (progressButtonEnabled) {
if (pager.getCurrentItem() == slidesNumber - 1) {
setButtonState(nextButton, false);
setButtonState(doneButton, true);
} else {
setButtonState(nextButton, true);
setButtonState(doneButton, false);
}
} else {
setButtonState(nextButton, false);
setButtonState(doneButton, false);
}
}
禁用向右滑动(滑动到下一页)
public void setNextPageSwipeLock(boolean lockEnable) {
if (lockEnable) {
// 如果锁定,保存按钮的显示情况,以备恢复锁定时使用
baseProgressButtonEnabled = progressButtonEnabled;
setProgressButtonEnabled(!lockEnable);
} else {
// 解除锁定后,恢复上一次保存的按钮显示状况
setProgressButtonEnabled(baseProgressButtonEnabled);
}
pager.setNextPagingEnabled(!lockEnable);
}
禁用滑动,而不只是禁用向右滑动
public void setSwipeLock(boolean lockEnable) {
if (lockEnable) {
// 如果锁定,保存按钮的显示情况,以备恢复锁定时使用
baseProgressButtonEnabled = progressButtonEnabled;
} else {
// 解除锁定后,恢复上一次保存的按钮显示状况
setProgressButtonEnabled(baseProgressButtonEnabled);
}
pager.setPagingEnabled(!lockEnable);
}
以及还有很多关于自定义底部按钮的方法,这里就省略了。
@Override
public void addOnPageChangeListener(OnPageChangeListener listener) {
super.addOnPageChangeListener(listener);
this.listener = listener;
}
@Override
public void setCurrentItem(int item) {
// 当设定 current item 为 0,即只有一个页面
// listener 需要我们自己调用
boolean invokeMeLater = false;
if (super.getCurrentItem() == 0 && item == 0)
invokeMeLater = true;
super.setCurrentItem(item);
if (invokeMeLater && listener != null)
listener.onPageSelected(0);
}
检测滑动方向
private boolean detectSwipeToRight(MotionEvent event) {
// 滑动距离初始为0
final int SWIPE_THRESHOLD = 0;
boolean result = false;
try {
float diffX = event.getX() - initialXValue;
if (Math.abs(diffX) > SWIPE_THRESHOLD) {
if (diffX < 0) {
result = true;
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
检查页面是否被设定为锁定,以便针对 MotionEvent 做出相应的反应
private boolean checkPagingState(MotionEvent event) {
if (!pagingEnabled) {
return true;
}
if (!nextPagingEnabled) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
initialXValue = event.getX();
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (detectSwipeToRight(event)) {
return true;
}
}
}
return false;
}
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:right="4.5dp" android:bottom="4.5dp" android:top="4dp">
<shape android:shape="oval" >
<!--dot_white_color-->
<solid android:color="#55222222"/><size android:width="8dp"
<!--dot_grey_color-->
<!--<solid android:color="#22222222"/><size android:width="8dp"-->
android:height="8dp" />
</shape>
</item>
<item android:right="5dp" android:bottom="5dp" android:top="4dp">
<shape android:shape="oval" >
<!--dot_white-->
<solid android:color="#ffffff"/><size android:width="8dp"
<!--dot_grey_color-->
<!--<solid android:color="#22000000"/><size android:width="8dp"-->
android:height="8dp" />
</shape>
</item>
</layer-list>
Dots 由 ArrayList<ImageView>
管理,遍历数组,将相应的位置的 dot 置为 selected 或 unselected。
@Override
public void selectPosition(int index) {
mCurrentposition = index;
for (int i = 0; i < mSlideCount; i++) {
int drawableId = (i == index) ? (R.drawable.indicator_dot_white) : (R.drawable.indicator_dot_grey);
Drawable drawable = ContextCompat.getDrawable(mContext, drawableId);
if (selectedDotColor != DEFAULT_COLOR && i == index)
drawable.mutate().setColorFilter(selectedDotColor, PorterDuff.Mode.SRC_IN);
if (unselectedDotColor != DEFAULT_COLOR && i != index)
drawable.mutate().setColorFilter(unselectedDotColor, PorterDuff.Mode.SRC_IN);
mDots.get(i).setImageDrawable(drawable);
}
}
以及初始化 Dots
@Override
public void initialize(int slideCount) {
mDots = new ArrayList<>();
mSlideCount = slideCount;
selectedDotColor = -1;
unselectedDotColor = -1;
for (int i = 0; i < slideCount; i++) {
ImageView dot = new ImageView(mContext);
dot.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.indicator_dot_grey));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
mDotLayout.addView(dot, params);
mDots.add(dot);
}
selectPosition(FIRST_PAGE_NUM);
}
getItem()
和 getCount()
FLOW
、SLIDE_OVER
、DEPTH
、ZOOM
、FADE
一些其他的类
看完这个库基本了解了平时看到的顶部 Tab 与页面的切换的实现。关于动画部分不了解所以就 省略了。关于 ViewPager 的更多信息大家可以点下面的参考链接