最近要在公司的項(xiàng)目中實(shí)現(xiàn)這種效果英妓,就自己動(dòng)手實(shí)現(xiàn)了一下挽放。
使用
GraphicDetailsLayout gdLayout = (GraphicDetailsLayout) findViewById(R.id.gdlayout);
gdLayout.addFragment(new Fragment[] {new SpFragment(), new DeFragment()}, getSupportFragmentManager());
還是很簡(jiǎn)單的,把上下兩個(gè)fragment添加到GraphicDetailsLayout 中就可以了
思路
從效果中可以看到上下兩個(gè)控件都是可以滾動(dòng)的蔓纠,初始化狀態(tài)下辑畦,下面的控件是隱藏在屏幕下面的;那我們?cè)O(shè)計(jì)最外面的布局是LinearLayout贺纲,然后LinearLayout里面放兩個(gè)ScrollView航闺,ScrollView滾動(dòng)到頂部或頂部的時(shí)候,告訴LinearLayout攔截事件猴誊,來實(shí)現(xiàn)兩個(gè)ScrollView的上下拖動(dòng)效果。
實(shí)現(xiàn)
首先自定義一個(gè)ScrollView
public class GDScrollView extends ScrollView {
private LinearLayout mLl;
private int mLlHeight;
public static final String TAG_ONE = "up";
public static final String TAG_TWO = "down";
public static final int ID_ONE = 11111;
public static final int ID_TWO = 22222;
private GraphicDetailsLayout.ScrollListener mScrollListener;
public GDScrollView(Context context) {
super(context); }
public GDScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GDScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public GDScrollView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setScrollListener(GraphicDetailsLayout.ScrollListener scrollListener) {
mScrollListener = scrollListener;
}
public void addFragment(Fragment fragment, FragmentManager fragmentManager) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if(mLl == null) mLl = (LinearLayout) getChildAt(0);
fragmentTransaction.replace(mLl.getId(), fragment);
fragmentTransaction.commit(); }
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mLlHeight = mLl.getMeasuredHeight();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mLl = (LinearLayout) getChildAt(0);
}
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
if(getTag().equals(TAG_ONE)) {
//上面的界面滾動(dòng)到底部的時(shí)候
if(isScrollBottom()) {
criticalPointOperation(false, true, TAG_ONE);
}
}
if(getTag().equals(TAG_TWO)) {
//下面的界面滾動(dòng)到頂部的時(shí)候
if(getScrollY() <= 0) {
criticalPointOperation(false, true, TAG_TWO);
}
}
}
private void criticalPointOperation(boolean allow, boolean intercept, String tag) {
getParent().requestDisallowInterceptTouchEvent(allow);
if(mScrollListener != null) mScrollListener.scrollBottom(intercept, tag); }
public boolean isScrollBottom() {
return getScrollY() >= (mLlHeight - getMeasuredHeight());
}
}
重寫onOverScrolled方法監(jiān)控滾動(dòng)的狀態(tài)侮措,判斷不同的ScrollView滾動(dòng)到頂部或者頂部觸發(fā)回調(diào)事件懈叹,把觸摸事件交給上層LinarLayout控件,來看看LinearLayout的onTouchEvent方法
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
if(mInitY == 0) {
mInitY = event.getY();
} else {
int offset = (int) Math.abs(event.getY() - mInitY);
if(offset > mTouchSlop) {
int delayOffset = offset * 7 / 10;
if(mCurrentTag.equals(GDScrollView.TAG_ONE)) {
mUpSVMarginTop = mInitMarginTop - delayOffset;
} else {
mUpSVMarginTop = - halfHeight + delayOffset;
}
if(mUpSVMarginTop > 0) mUpSVMarginTop = 0;
requestLayout();
}
}
break;
case MotionEvent.ACTION_UP:
mIntercept = false;
mInitY = 0;
if(mCurrentTag.equals(GDScrollView.TAG_ONE)) {
if(Math.abs(mUpSVMarginTop) > halfHeight / 3) {
startAnimation(mUpSVMarginTop, halfHeight - Math.abs(mUpSVMarginTop), false);
} else {
startAnimation(mUpSVMarginTop, Math.abs(mUpSVMarginTop), true);
}
} else {
if(Math.abs(mUpSVMarginTop) < halfHeight * 2 / 3) {
startAnimation(mUpSVMarginTop, Math.abs(mUpSVMarginTop), true);
} else {
startAnimation(mUpSVMarginTop, halfHeight - Math.abs(mUpSVMarginTop), false);
}
}
requestLayout();
break;
}
return true;
}
LinearLayout攔截到事件以后重寫onTouchEvent方法分扎,通過手勢(shì)拖動(dòng)來不斷的計(jì)算ScrooView距離頂部的高度mUpSVMarginTop澄成,調(diào)用requestLayout方法發(fā)起重新布局,重寫onLayout方法
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
halfHeight = getMeasuredHeight() / 2;
mUpScrollView.layout(0, mUpSVMarginTop, getMeasuredWidth(), mUpSVMarginTop + halfHeight);
mBottomScrollView.layout(0, mUpSVMarginTop + halfHeight , getMeasuredWidth(), mUpSVMarginTop + getMeasuredHeight());}
大致的思路和實(shí)現(xiàn)已經(jīng)講解完成了畏吓,想看具體實(shí)現(xiàn)代碼
https://github.com/chenpengfei88/GraphicDetailsLayout
歡迎start墨状,follow。