最近项目需求类似于淘宝中的继续拖动,显示详情页面,就是当activity滑动到底部时,会出来另一个webview,这其中可能会出现scrollview和webview冲突。
效果图如下:
MainActivity代码:
package com.stone.verticalslide;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Window;
import com.stone.verticalslide.DragLayout.ShowNextPageNotifier;
public class MainActivity extends FragmentActivity {
private VerticalFragment1 fragment1;
private VerticalFragment3 fragment3;
private DragLayout draglayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
initView();
}
/**
* 初始化View
*/
private void initView() {
fragment1 = new VerticalFragment1();
fragment3 = new VerticalFragment3();
getSupportFragmentManager().beginTransaction()
.add(R.id.first, fragment1).add(R.id.second, fragment3)
.commit();
ShowNextPageNotifier nextIntf = new ShowNextPageNotifier() {
@Override
public void onDragNext() {
fragment3.initView();
}
};
draglayout = (DragLayout) findViewById(R.id.draglayout);
draglayout.setNextPageListener(nextIntf);
}
}
MainActivity的xml文件代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="50dp"
android:background="#1fa9a6"
android:gravity="center"
android:text="商品详情"
android:textColor="#fff"
android:textSize="18sp"
android:textStyle="bold" />
<View
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="#aaaaaa" />
<com.stone.verticalslide.DragLayout
android:id="@+id/draglayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
<FrameLayout
android:id="@+id/first"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<FrameLayout
android:id="@+id/second"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</com.stone.verticalslide.DragLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="#aaa" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dp"
android:background="#fff"
android:gravity="center_vertical"
android:orientation="horizontal" >
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:gravity="left"
android:text="¥28.00"
android:textColor="#f00" />
<TextView
android:layout_width="110dp"
android:layout_height="35dp"
android:layout_marginLeft="10dp"
android:background="#ff0000"
android:gravity="center"
android:text="加入购物车"
android:textColor="#fff"
android:textSize="18sp" />
<TextView
android:layout_width="90dp"
android:layout_height="35dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="#454545"
android:drawableLeft="@drawable/qq"
android:gravity="center"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="客服"
android:textColor="#fff"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
两个碎片代码:
第一个碎片:
package com.stone.verticalslide;
import android.graphics.Paint;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class VerticalFragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.vertical_fragment1, null);
TextView oldTextView = (TextView) rootView
.findViewById(R.id.old_textview);
oldTextView.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
return rootView;
}
}
碎片的xml文件代码:
<?xml version="1.0" encoding="utf-8"?>
<com.stone.verticalslide.CustScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/custScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="220dp"
android:background="@drawable/img001" >
<TextView
android:layout_width="33dp"
android:layout_height="28dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:background="@drawable/alpha_circle"
android:gravity="center"
android:text="1/4"
android:textColor="#fff" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:background="#3f000000"
android:gravity="center_vertical"
android:orientation="horizontal" >
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:text="THE FACE SHOP菲诗小铺深层清洁洁面乳170ml"
android:textColor="#fff"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:drawablePadding="5dp"
android:drawableTop="@drawable/share_button"
android:text="分享"
android:textColor="#fff" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:drawablePadding="5dp"
android:drawableTop="@drawable/love"
android:text="收藏"
android:textColor="#fff" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="60dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center_horizontal"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="¥28.00"
android:textColor="#f00"
android:textSize="16sp" />
<TextView
android:id="@+id/old_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="¥28.00 "
android:textColor="#888"
android:textSize="16sp" />
</LinearLayout>
<TextView
android:layout_width="50dp"
android:layout_height="22dp"
android:layout_marginTop="5dp"
android:background="#ec616c"
android:gravity="center"
android:text="包邮"
android:textColor="#fff" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="20dp"
android:gravity="center_horizontal"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="22dp"
android:gravity="center"
android:text="已售出 28303 件"
android:textColor="#999" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="库存:1354件"
android:textColor="#999" />
</LinearLayout>
</RelativeLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="#ddd" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="44dp"
android:gravity="center_vertical"
android:orientation="horizontal" >
<View
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="10dp"
android:background="@drawable/goods_introduction" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="商品简介"
android:textColor="#444" />
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="#ddd" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:lineSpacingExtra="5dp"
android:text="商品名称:THE FACE SHOP菲诗小铺深层清洁洁面乳170ml\n品牌:菲诗小铺\n适用肤质:油性肌肤、混合肌肤\n产地:中国\n生产日期:详见商品包装\n保质期:三年\n包装方式:无盒塑封"
android:textColor="#888" />
<View
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="#ddd" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="44dp"
android:gravity="center_vertical"
android:orientation="horizontal" >
<View
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="10dp"
android:background="@drawable/comment" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="商品评价 (6314)"
android:textColor="#444" />
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="#ddd" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:paddingTop="5dp" >
<View
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="14dp"
android:background="@drawable/head" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="182***@qq.com"
android:textColor="#999" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="油性发质"
android:textColor="#999" />
<RatingBar
style="?android:attr/ratingBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:numStars="5" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="14dp"
android:layout_marginTop="5dp"
android:lineSpacingExtra="5dp"
android:text="这个真的是全五星级的宝贝啊,白菜价格,超级大的一瓶,真的是超乎你的想象,我买的樱桃的,非常喜欢,膏体是淡淡的粉色,泡沫很细腻,配上丽子送的..."
android:textColor="#555" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="8dp"
android:paddingTop="5dp" >
<View
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginLeft="14dp"
android:background="@drawable/capture01" />
<View
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginLeft="14dp"
android:background="@drawable/capture02" />
<View
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginLeft="14dp"
android:background="@drawable/capture03" />
<View
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginLeft="14dp"
android:background="@drawable/capture04" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingTop="5dp" >
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="14dp"
android:layout_weight="1"
android:text="樱桃"
android:textColor="#888" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:text="2015-01-15 10:12:50"
android:textColor="#888" />
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="#ddd" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingTop="10dp" >
<View
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginLeft="14dp"
android:background="@drawable/official" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="官方直营"
android:textColor="#444" />
<RatingBar
style="?android:attr/ratingBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:numStars="5"
android:rating="5" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#f57c86"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:text="全场包邮"
android:textColor="#fff" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:background="#f57c86"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:text="48小时发货"
android:textColor="#fff" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:background="#f57c86"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:text="30天退换货"
android:textColor="#fff" />
</LinearLayout>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="进店\n看看"
android:textColor="#888" />
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="#ddd" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dp"
android:background="#fafafa"
android:gravity="center_vertical"
android:orientation="horizontal" >
<View
android:layout_width="0dp"
android:layout_height="1px"
android:layout_weight="1"
android:background="#ddd" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:text="继续拖动,查看图文详情"
android:textColor="#777"
android:textSize="13sp" />
<View
android:layout_width="0dp"
android:layout_height="1px"
android:layout_weight="1"
android:background="#ddd" />
</LinearLayout>
</LinearLayout>
</com.stone.verticalslide.CustScrollView>
第二个碎片代码:
package com.stone.verticalslide;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class VerticalFragment3 extends Fragment {
private View progressBar;
private CustWebView webview;
private boolean hasInited = false;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.vertical_fragment3, null);
webview = (CustWebView) rootView.findViewById(R.id.fragment3_webview);
progressBar = rootView.findViewById(R.id.progressbar);
return rootView;
}
public void initView() {
if (null != webview && !hasInited) {
hasInited = true;
progressBar.setVisibility(View.GONE);
webview.loadUrl("http://m.zol.com/tuan/");
}
}
}
碎片的xml文件代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.stone.verticalslide.CustWebView
android:id="@+id/fragment3_webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<ProgressBar
android:id="@+id/progressbar"
style="@android:style/Widget.ProgressBar.Inverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_centerHorizontal="true" />
</RelativeLayout>
核心类DragLayout 可以装载两个碎片,实现我们要的效果:
package com.stone.verticalslide;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
/**
* 这是一个viewGroup容器,实现上下两个frameLayout拖动切换
*
* @author sistone.Zhang
*/
@SuppressLint("NewApi")
public class DragLayout extends ViewGroup {
/* 拖拽工具类 */
private final ViewDragHelper mDragHelper;
private GestureDetectorCompat gestureDetector;
/* 上下两个frameLayout,在Activity中注入fragment */
private View frameView1, frameView2;
private int viewHeight;
private static final int VEL_THRESHOLD = 100; // 滑动速度的阈值,超过这个绝对值认为是上下
private static final int DISTANCE_THRESHOLD = 100; // 单位是像素,当上下滑动速度不够时,通过这个阈值来判定是应该粘到顶部还是底部
private int downTop1; // 手指按下的时候,frameView1的getTop值
private ShowNextPageNotifier nextPageListener; // 手指松开是否加载下一页的notifier
public DragLayout(Context context) {
this(context, null);
}
public DragLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DragLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDragHelper = ViewDragHelper
.create(this, 10f, new DragHelperCallback());
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_BOTTOM);
gestureDetector = new GestureDetectorCompat(context,
new YScrollDetector());
}
@Override
protected void onFinishInflate() {
// 跟findviewbyId一样,初始化上下两个view
frameView1 = getChildAt(0);
frameView2 = getChildAt(1);
}
class YScrollDetector extends SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx,
float dy) {
// 垂直滑动时dy>dx,才被认定是上下拖动
return Math.abs(dy) > Math.abs(dx);
}
}
@Override
public void computeScroll() {
if (mDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
/**
* 这是拖拽效果的主要逻辑
*/
private class DragHelperCallback extends ViewDragHelper.Callback {
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
int childIndex = 1;
if (changedView == frameView2) {
childIndex = 2;
}
// 一个view位置改变,另一个view的位置要跟进
onViewPosChanged(childIndex, top);
}
@Override
public boolean tryCaptureView(View child, int pointerId) {
// 两个子View都需要跟踪,返回true
return true;
}
@Override
public int getViewVerticalDragRange(View child) {
// 这个用来控制拖拽过程中松手后,自动滑行的速度,暂时给一个随意的数值
return 1;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
// 滑动松开后,需要向上或者乡下粘到特定的位置
animTopOrBottom(releasedChild, yvel);
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
int finalTop = top;
if (child == frameView1) {
// 拖动的时第一个view
if (top > 0) {
// 不让第一个view往下拖,因为顶部会白板
finalTop = 0;
}
} else if (child == frameView2) {
// 拖动的时第二个view
if (top < 0) {
// 不让第二个view网上拖,因为底部会白板
finalTop = 0;
}
}
// finalTop代表的是理论上应该拖动到的位置。此处计算拖动的距离除以一个参数(3),是让滑动的速度变慢。数值越大,滑动的越慢
return child.getTop() + (finalTop - child.getTop()) / 3;
}
}
/**
* 滑动时view位置改变协调处理
*
* @param viewIndex
* 滑动view的index(1或2)
* @param posTop
* 滑动View的top位置
*/
private void onViewPosChanged(int viewIndex, int posTop) {
if (viewIndex == 1) {
int offsetTopBottom = viewHeight + frameView1.getTop()
- frameView2.getTop();
frameView2.offsetTopAndBottom(offsetTopBottom);
} else if (viewIndex == 2) {
int offsetTopBottom = frameView2.getTop() - viewHeight
- frameView1.getTop();
frameView1.offsetTopAndBottom(offsetTopBottom);
}
// 有的时候会默认白板,这个很恶心。后面有时间再优化
invalidate();
}
private void animTopOrBottom(View releasedChild, float yvel) {
int finalTop = 0; // 默认是粘到最顶端
if (releasedChild == frameView1) {
// 拖动第一个view松手
if (yvel < -VEL_THRESHOLD
|| (downTop1 == 0 && frameView1.getTop() < -DISTANCE_THRESHOLD)) {
// 向上的速度足够大,就滑动到顶端
// 向上滑动的距离超过某个阈值,就滑动到顶端
finalTop = -viewHeight;
// 下一页可以初始化了
if (null != nextPageListener) {
nextPageListener.onDragNext();
}
}
} else {
// 拖动第二个view松手
if (yvel > VEL_THRESHOLD
|| (downTop1 == -viewHeight && releasedChild.getTop() > DISTANCE_THRESHOLD)) {
// 保持原地不动
finalTop = viewHeight;
}
}
if (mDragHelper.smoothSlideViewTo(releasedChild, 0, finalTop)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
/* touch事件的拦截与处理都交给mDraghelper来处理 */
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (frameView1.getBottom() > 0 && frameView1.getTop() < 0) {
// view粘到顶部或底部,正在动画中的时候,不处理touch事件
return false;
}
boolean yScroll = gestureDetector.onTouchEvent(ev);
boolean shouldIntercept = mDragHelper.shouldInterceptTouchEvent(ev);
int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
// action_down时就让mDragHelper开始工作,否则有时候导致异常 他大爷的
mDragHelper.processTouchEvent(ev);
downTop1 = frameView1.getTop();
}
return shouldIntercept && yScroll;
}
@Override
public boolean onTouchEvent(MotionEvent e) {
// 统一交给mDragHelper处理,由DragHelperCallback实现拖动效果
mDragHelper.processTouchEvent(e); // 该行代码可能会抛异常,正式发布时请将这行代码加上try catch
return true;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 只在初始化的时候调用
// 一些参数作为全局变量保存起来
if (frameView1.getTop() == 0) {
// 只在初始化的时候调用
// 一些参数作为全局变量保存起来
frameView1.layout(l, 0, r, b - t);
frameView2.layout(l, 0, r, b - t);
viewHeight = frameView1.getMeasuredHeight();
frameView2.offsetTopAndBottom(viewHeight);
} else {
// 如果已被初始化,这次onLayout只需要将之前的状态存入即可
frameView1.layout(l, frameView1.getTop(), r, frameView1.getBottom());
frameView2.layout(l, frameView2.getTop(), r, frameView2.getBottom());
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(
resolveSizeAndState(maxWidth, widthMeasureSpec, 0),
resolveSizeAndState(maxHeight, heightMeasureSpec, 0));
}
/**
* 这是View的方法,该方法不支持android低版本(2.2、2.3)的操作系统,所以手动复制过来以免强制退出
*/
public static int resolveSizeAndState(int size, int measureSpec,
int childMeasuredState) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
if (specSize < size) {
result = specSize | MEASURED_STATE_TOO_SMALL;
} else {
result = size;
}
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result | (childMeasuredState & MEASURED_STATE_MASK);
}
public void setNextPageListener(ShowNextPageNotifier nextPageListener) {
this.nextPageListener = nextPageListener;
}
public interface ShowNextPageNotifier {
public void onDragNext();
}
}
自定义的ScrollView:
package com.stone.verticalslide;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;
public class CustScrollView extends ScrollView {
boolean allowDragBottom = true; // 如果是true,则允许拖动至底部的下一页
float downY = 0;
boolean needConsumeTouch = true; // 是否需要承包touch事件,needConsumeTouch一旦被定性,则不会更改
int maxScroll = -1; // 最大滑动距离
public CustScrollView(Context arg0) {
this(arg0, null);
}
public CustScrollView(Context arg0, AttributeSet arg1) {
this(arg0, arg1, 0);
}
public CustScrollView(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
downY = ev.getRawY();
needConsumeTouch = true; // 默认情况下,scrollView内部的滚动优先,默认情况下由该ScrollView去消费touch事件
if (maxScroll > 0
&& getScrollY() + getMeasuredHeight() >= maxScroll - 2) {
// 允许向上拖动底部的下一页
allowDragBottom = true;
} else {
// 不允许向上拖动底部的下一页
allowDragBottom = false;
}
} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
if (!needConsumeTouch) {
// 在最顶端且向上拉了,则这个touch事件交给父类去处理
getParent().requestDisallowInterceptTouchEvent(false);
return false;
} else if (allowDragBottom) {
// needConsumeTouch尚未被定性,此处给其定性
// 允许拖动到底部的下一页,而且又向上拖动了,就将touch事件交给父view
if (downY - ev.getRawY() > 2) {
// flag设置,由父类去消费
needConsumeTouch = false;
getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
}
}
// 通知父view是否要处理touch事件
getParent().requestDisallowInterceptTouchEvent(needConsumeTouch);
return super.dispatchTouchEvent(ev);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
if (maxScroll < 0) {
maxScroll = computeVerticalScrollRange();
}
super.onScrollChanged(l, t, oldl, oldt);
}
}
自定义的WebView
package com.stone.verticalslide;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.webkit.WebView;
public class CustWebView extends WebView {
boolean allowDragTop = true; // 如果是true,则允许拖动至底部的下一页
float downY = 0;
boolean needConsumeTouch = true; // 是否需要承包touch事件,needConsumeTouch一旦被定性,则不会更改
public CustWebView(Context arg0) {
this(arg0, null);
}
public CustWebView(Context arg0, AttributeSet arg1) {
this(arg0, arg1, 0);
}
public CustWebView(Context arg0, AttributeSet arg1, int arg2) {
super(arg0, arg1, arg2);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
downY = ev.getRawY();
needConsumeTouch = true; // 默认情况下,listView内部的滚动优先,默认情况下由该listView去消费touch事件
allowDragTop = isAtTop();
} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
if (!needConsumeTouch) {
// 在最顶端且向上拉了,则这个touch事件交给父类去处理
getParent().requestDisallowInterceptTouchEvent(false);
return false;
} else if (allowDragTop) {
// needConsumeTouch尚未被定性,此处给其定性
// 允许拖动到底部的下一页,而且又向上拖动了,就将touch事件交给父view
if (ev.getRawY() - downY > 2) {
// flag设置,由父类去消费
needConsumeTouch = false;
getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
}
}
// 通知父view是否要处理touch事件
getParent().requestDisallowInterceptTouchEvent(needConsumeTouch);
return super.dispatchTouchEvent(ev);
}
/**
* 判断listView是否在顶部
*
* @return 是否在顶部
*/
private boolean isAtTop() {
return getScrollY() == 0;
}
}