Viewpager只能横向滑动,如果是要竖向滑动呢,那么立马会想到ScrollView ,但是都知道ScrollView滑动并没有判断一页一页分屏滑动,今天来自定义一个ViewGroup实现这个功能。
先看效果:
布局文件
<?xml version="1.0" encoding="utf-8"?>
<com.example.apple.Custom.VerticalViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:id="@+id/custom"
android:layout_height="match_parent"
tools:context="com.example.apple.Custom.VerticalActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg1" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg2" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg3" />
</com.example.apple.Custom.VerticalViewPager>
关键自定义类
package com.example.apple.Custom;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ScrollView;
import android.widget.Scroller;
/**
* Created by apple on 17/9/16.
*/
public class VerticalViewPager extends ViewGroup {
OnPageChangeListener lis;
int mScreenHeight;//屏幕的高
Scroller mscroller;
int startScroll;
int downY;
int lastPos = -1;
boolean isTouchDown;
public VerticalViewPager(Context context) {
super(context);
init(context);
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public VerticalViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenHeight = outMetrics.heightPixels;
mscroller = new Scroller(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int count = getChildCount();
for (int i = 0; i < count; ++i) {
View childView = getChildAt(i);
measureChild(childView, widthMeasureSpec, mScreenHeight);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
int childCount = getChildCount();
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
lp.height = mScreenHeight * childCount;
setLayoutParams(lp);
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
child.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight);// 调用每个自布局的layout
}
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int cy = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!mscroller.isFinished())
return true;
downY = (int) event.getY();
startScroll = getScrollY();
isTouchDown = true;
break;
case MotionEvent.ACTION_MOVE:
int scrollY = getScrollY();
int dy = downY - cy;
//向下滑动到最顶端的时候,这里注意,scrollY只用这一个判断,布局会跳动。
if (dy < 0 && scrollY + dy < 0) {
dy = -scrollY;
}
// 向上滑动,滑动到最底端的时候,布局不能继续向上移动了,getHeight这个高是整个view的高度,在这里也就是n个屏高度。
if (dy > 0 && scrollY + dy > getHeight() - mScreenHeight) {
dy = getHeight() - mScreenHeight - scrollY;
}
scrollBy(0, dy);
downY = cy;
break;
case MotionEvent.ACTION_UP:
int endScrolly = getScrollY();
int durscrolly = endScrolly - startScroll;
if (endScrolly > startScroll) {//向上滑动
if (durscrolly > mScreenHeight / 2) {//滑动距离又没有大于半个屏高,切换相应的页面
mscroller.startScroll(0, getScrollY(), 0, mScreenHeight - durscrolly);
} else {
mscroller.startScroll(0, getScrollY(), 0, -durscrolly);
}
}
if (startScroll > endScrolly) {下滑
if (Math.abs(durscrolly) > mScreenHeight / 2) {
mscroller.startScroll(0, getScrollY(), 0, -durscrolly - mScreenHeight);
} else {
mscroller.startScroll(0, getScrollY(), 0, -durscrolly);
}
}
postInvalidate();
isTouchDown = false;
break;
}
return true;
}
@Override
public void computeScroll() {
super.computeScroll();
if (mscroller != null && mscroller.computeScrollOffset()) {
scrollTo(0, mscroller.getCurrY());
postInvalidate();
} else {
if (isTouchDown) return;
int scrollY = getScrollY();
int i = scrollY / mScreenHeight;
if (lastPos == i) return;
if (lis != null) {
lis.onPageChange(i);
}
lastPos = i;
}
}
public void setPageChangeListener(OnPageChangeListener lis) {
this.lis = lis;
}
public interface OnPageChangeListener {
void onPageChange(int currentPage);
}
}
关键代码就这么多,这里只需要注意scroller的用法,滑动工具类。