上下拖拽切换布局

  
  
package cn..widget;
 
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;
 
/**
*
* 详情页的 SlidingDetailsLayout 和 {@link DetailsScrollView } 搭配使用
* 包裹 两个实现{@link TopBottomListener} 的布局 达到上下拖拽切换布局的问题
* WebView 直接使用的是{@link cn.TuHu.SafeWebViewBridge.jsbridge.BridgeWebView}
* SlidingDetailsLayout解决的了CoreLayout事件分发导致ViewPager嵌套的问题
* 参考 https://github.com/turing-king/PullupSeeDetails
*/
public class SlidingDetailsLayout extends ViewGroup {
/**
* 用于完成滚动操作的实例
*/
private Scroller mScroller;
 
/**
* 手机按下时的屏幕坐标
*/
private float mYDown;
 
/**
* 手机当时所处的屏幕坐标
*/
private float mYMove;
 
/**
* 上次触发ACTION_MOVE事件时的屏幕坐标
*/
private float mYLastMove;
 
//顶部的view 底部的view
private View topView, bottomView;
// private View promptView;
 
//当前所在的索引
private int position = 0;
 
private TopBottomListener topListener, bottomListener;
 
private PositionChangListener positionChangListener;
 
private int mTouchSlop;
 
/**
* 监听view是否到了顶部或者底部
*/
public interface TopBottomListener {
boolean isScrollTop();//已经到了顶部
 
boolean isScrollBottom();//已经到了底部
 
void scrollToTop();//滚动到顶部
 
void scrollToBottom();//滚动到底部
}
 
public interface PositionChangListener {
void position(int position);
void onBottom();
void backBottom();
void onTop();
void backTop();
}
 
public SlidingDetailsLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// 第一步,创建Scroller的实例
mScroller = new Scroller(context);
 
ViewConfiguration vc = ViewConfiguration.get(context);
mTouchSlop = vc.getScaledTouchSlop();
}
 
public void setPositionChangListener(PositionChangListener positionChangListener) {
this.positionChangListener = positionChangListener;
}
 
 
@Override
protected void onFinishInflate() {
//获取 三个view 并计算 promptView 的宽高
topView = getChildAt(0);
// promptView = getChildAt(1);
bottomView = getChildAt(1);
 
//topView 和 bottomView 必须继承 TopBottomListener 接口
if (topView instanceof TopBottomListener) {
topListener = (TopBottomListener) topView;
}
if (bottomView instanceof TopBottomListener) {
bottomListener = (TopBottomListener) bottomView;
}
super.onFinishInflate();
}
 
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childCount = this.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
 
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//布局 topView和bottomView宽高都是充满父view
topView.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
// promptView.layout(0, getMeasuredHeight(), promptView.getMeasuredWidth(), getMeasuredHeight() + promptView.getMeasuredHeight());
bottomView.layout(0, getMeasuredHeight() /*+ promptView.getMeasuredHeight()*/, getMeasuredWidth(), 2 * getMeasuredHeight() /*+ promptView.getMeasuredHeight()*/);
}
 
public boolean dispatchTouchEventSupper(MotionEvent e) {
return super.dispatchTouchEvent(e);
}
 
private boolean top, bottom;
 
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mYDown = ev.getRawY();
mYLastMove = mYDown;
break;
 
case MotionEvent.ACTION_MOVE:
mYMove = ev.getRawY();
int scrolledY = (int) (mYLastMove - mYMove);
mYLastMove = mYMove;
//当前在第一页
if (position == 0) {
 
if (positionChangListener != null) {
if (getScrollY() + getHeight() > getHeight() /*+ promptView.getHeight()*/) {
if (!bottom) {
positionChangListener.onBottom();
bottom = true;
}
} else {
if (positionChangListener != null) {
positionChangListener.backBottom();
bottom = false;
}
}
}
 
if (topListener == null || topListener.isScrollBottom()) {
 
if (getScrollY() + scrolledY < topView.getTop()) {//不能移动超出topview的最上方
scrollTo(0, topView.getTop());
} else {
scrollBy(0, scrolledY);
if (getScrollY() != 0) {
return true;
}
}
}
} else {//底部view
if (positionChangListener != null) {
if (getScrollY() < getHeight()) {
if (!top) {
positionChangListener.onTop();
top = true;
}
} else {
if (top) {
positionChangListener.backTop();
top = false;
}
}
}
 
if (bottomListener == null || bottomListener.isScrollTop()) {//bottomView 已经移动到了顶部
 
 
if (getScrollY() + getHeight() + scrolledY > bottomView.getBottom()) {
scrollTo(0, bottomView.getBottom() - getHeight());
} else {
scrollBy(0, scrolledY);
if (getScrollY() != getHeight() /*+ promptView.getHeight()*/) {
return true;
}
}
}
}
break;
 
case MotionEvent.ACTION_UP:
// 当手指抬起时,根据当前的滚动值来判定应该滚动到哪个子控件的界面
int targetIndex;
 
if (position == 0) {
targetIndex = getScrollY() + getHeight() > getHeight() /*+ promptView.getHeight()*/ ? 1 : 0;
 
} else {
targetIndex = getScrollY() < getHeight() ? 0 : 1;
 
}
position = targetIndex;
 
int dy;
if (targetIndex == 0) {
dy = targetIndex * getHeight() - getScrollY();
} else {
dy = targetIndex * getHeight() /*+ promptView.getHeight() */ - getScrollY();
}
 
// 第二步,调用startScroll()方法来初始化滚动数据并刷新界面
mScroller.startScroll(0, getScrollY(), 0, dy);
invalidate();
 
if (positionChangListener != null) {
positionChangListener.position(position);
}
 
if (getScrollY() != 0 && getScrollY() != getHeight() /*+ promptView.getHeight()*/) {//如果处在滑动状态 就不要传递事件给子view
return true;
}
 
break;
}
return super.dispatchTouchEvent(ev);
}
 
@Override
public void computeScroll() {
// 第三步,重写computeScroll()方法,并在其内部完成平滑滚动的逻辑
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}
}
   
   
使用:
mSlidingDetailsLayout.setPositionChangListener(new SlidingDetailsLayout.PositionChangListener() {
@Override
public void position(int position) {
if (1 == position) {
if (isLoadWeb) {
mBridgeWebView.loadUrl(mDetailUrl);
}
}
}
 
@Override
public void onBottom() {
 
}
 
@Override
public void backBottom() {
 
}
 
@Override
public void onTop() {
 
}
 
@Override
public void backTop() {
 
}
});
    
    
package cn..widget;
 
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;
 
/**
* 详情页的 ScrollView 和 {@link SlidingDetailsLayout } 搭配使用
* Webview 直接使用的是{@link cn.TuHu.SafeWebViewBridge.jsbridge.BridgeWebView}
* 参考 https://github.com/turing-king/PullupSeeDetails
*/
public class DetailsScrollView extends ScrollView implements SlidingDetailsLayout.TopBottomListener {
 
private boolean top, bottom;
 
public DetailsScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
top = false;
bottom = false;
}
 
@Override
public boolean isScrollTop() {
return top;
}
 
@Override
public boolean isScrollBottom() {
return bottom;
}
 
@Override
public void scrollToTop() {
fullScroll(View.FOCUS_UP);
}
 
@Override
public void scrollToBottom() {
fullScroll(View.FOCUS_DOWN);
}
 
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
 
if (getChildAt(0).getHeight() < getHeight()) {
top = true;
bottom = true;
} else {
top = getScrollY() == 0;
int diff = (getChildAt(0).getBottom() - (getHeight() + getScrollY()));
bottom = diff == 0;
}
}
 
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
 
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
top = getScrollY() == 0;
int diff = (getChildAt(0).getBottom() - (getHeight() + getScrollY()));
bottom = diff == 0;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值