ScrollView中嵌套ViewPager,ViewPager中使用FlowLayout

之前做过一个viewpager嵌套页面:可上下滑动的Layout中嵌套一个自定义的ViewPager,viewPager中嵌套FlowLayout。

整体效果如下图1所示。


上滑到顶部效果如图2:


代码清单文件如下:

1.ScrollableLayout.java

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.LinearLayout;
import android.widget.Scroller;

public class ScrollableLayout extends LinearLayout {

    private final String tag = "cp:scrollableLayout";
    private float mDownX;
    private float mDownY;
    private float mLastY;

    private int minY = 0;
    private int maxY = 0;
    private int mHeadHeight;
    private int mExpandHeight;
    private int mTouchSlop;
    private int mMinimumVelocity;
    private int mMaximumVelocity;
    // 方向
    private DIRECTION mDirection;
    private int mCurY;
    private int mLastScrollerY;
    private boolean needCheckUpdown;
    private boolean updown;
    private boolean mDisallowIntercept;
    private boolean isClickHead;
    private boolean isClickHeadExpand;

    private View mHeadView;
    private ViewPager childViewPager;

    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;

    /**
     * 滑动方向 *
     */
    enum DIRECTION {
        UP,// 向上划
        DOWN// 向下划
    }

    public interface OnScrollListener {

        void onScroll(int currentY, int maxY);

    }

    private OnScrollListener onScrollListener;

    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }

    private ScrollableHelper mHelper;

    public ScrollableHelper getHelper() {
        return mHelper;
    }

    public ScrollableLayout(Context context) {
        super(context);
        init(context);
    }

    public ScrollableLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public ScrollableLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ScrollableLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }

    private void init(Context context) {
        mHelper = new ScrollableHelper();
        mScroller = new Scroller(context);
        final ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = configuration.getScaledTouchSlop();
        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
    }

    public boolean isSticked() {
        return mCurY == maxY;
    }

    /**
     * 扩大头部点击滑动范围
     *
     * @param expandHeight
     */
    public void setClickHeadExpand(int expandHeight) {
        mExpandHeight = expandHeight;
    }

    public int getMaxY() {
        return maxY;
    }

    public boolean isHeadTop() {
        return mCurY == minY;
    }

    public boolean canPtr() {
        return updown && mCurY == minY && mHelper.isTop();
    }

    public void requestScrollableLayoutDisallowInterceptTouchEvent(boolean disallowIntercept) {
        super.requestDisallowInterceptTouchEvent(disallowIntercept);
        mDisallowIntercept = disallowIntercept;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        float currentX = ev.getX();
        float currentY = ev.getY();
        float deltaY;
        int shiftX = (int) Math.abs(currentX - mDownX);
        int shiftY = (int) Math.abs(currentY - mDownY);
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDisallowIntercept = false;
                needCheckUpdown = true;
                updown = true;
                mDownX = currentX;
                mDownY = currentY;
                mLastY = currentY;
                checkIsClickHead((int) currentY, mHeadHeight, getScrollY());
                checkIsClickHeadExpand((int) currentY, mHeadHeight, getScrollY());
                initOrResetVelocityTracker();
                mVelocityTracker.addMovement(ev);
                mScroller.forceFinished(true);
                break;
            case MotionEvent.ACTION_MOVE:
                if (mDisallowIntercept) {
                    break;
                }
                initVelocityTrackerIfNotExists();
                mVelocityTracker.addMovement(ev);
                deltaY = mLastY - currentY;
                if (needCheckUpdown) {
                    if (shiftX > mTouchSlop && shiftX > shiftY) {
                        needCheckUpdown = false;
                        updown = false;
                    } else if (shiftY > mTouchSlop && shiftY > shiftX) {
                        needCheckUpdown = false;
                        updown = true;
                    }
                }

                if (updown && shiftY > mTouchSlop && shiftY > shiftX &&
                        (!isSticked() || mHelper.isTop() || isClickHeadExpand)) {

                    if (childViewPager != null) {
                        childViewPager.requestDisallowInterceptTouchEvent(true);
                    }
                    scrollBy(0, (int) (deltaY + 0.5));
                }
                mLastY = currentY;
                break;
            case MotionEvent.ACTION_UP:
                if (updown && shiftY > shiftX && shiftY > mTouchSlop) {
                    mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                    float yVelocity = -mVelocityTracker.getYVelocity();
                    boolean dislowChild = false;
                    if (Math.abs(yVelocity) > mMinimumVelocity) {
                        mDirection = yVelocity > 0 ? DIRECTION.UP : DIRECTION.DOWN;
                        if ((mDirection == DIRECTION.UP && isSticked()) || (!isSticked() && getScrollY() == 0 && mDirection == DIRECTION.DOWN)) {
                            dislowChild = true;
                        } else {
                            mScroller.fling(0, getScrollY(), 0, (int) yVelocity, 0, 0, -Integer.MAX_VALUE, Integer.MAX_VALUE);
                            mScroller.computeScrollOffset();
                            mLastScrollerY = getScrollY();
                            invalidate();
                        }
                    }
                    if (!dislowChild && (isClickHead || !isSticked())) {
                        int action = ev.getAction();
                        ev.setAction(MotionEvent.ACTION_CANCEL);
                        boolean dispathResult = super.dispatchTouchEvent(ev);
                        ev.setAction(action);
                        return dispathResult;
                    }
                }
                break;
            default:
                break;
        }
        super.dispatchTouchEvent(ev);
        return true;
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private int getScrollerVelocity(int distance, int duration) {
        if (mScroller == null) {
            return 0;
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            return (int) mScroller.getCurrVelocity();
        } else {
            return distance / duration;
        }
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            final int currY = mScroller.getCurrY();
            if (mDirection == DIRECTION.UP) {
                // 手势向上划
                if (isSticked()) {
                    int distance = mScroller.getFinalY() - currY;
                    int duration = calcDuration(mScroller.getDuration(), mScroller.timePassed());
                    mHelper.smoothScrollBy(getScrollerVelocity(distance, duration), distance, duration);
                    mScroller.forceFinished(true);
                    return;
                } else {
                    scrollTo(0, currY);
                }
            } else {
                // 手势向下划
                if (mHelper.isTop() || isClickHeadExpand) {
                    int deltaY = (currY - mLastScrollerY);
                    int toY = getScrollY() + deltaY;
                    scrollTo(0, toY);
                    if (mCurY <= minY) {
                        mScroller.forceFinished(true);
                        return;
                    }
                }
                invalidate();
            }
            mLastScrollerY = currY;
        }
    }

    @Override
    public void scrollBy(int x, int y) {
        int scrollY = getScrollY();
        int toY = scrollY + y;
        if (toY >= maxY) {
            toY = maxY;
        } else if (toY <= minY) {
            toY = minY;
        }
        y = toY - scrollY;
        super.scrollBy(x, y);
    }

    @Override
    public void scrollTo(int x, int y) {
        if (y >= maxY) {
            y = maxY;
        } else if (y <= minY) {
            y = minY;
        }
        mCurY = y;
        if (onScrollListener != null) {
            onScrollListener.onScroll(y, maxY);
        }
        super.scrollTo(x, y);
    }

    private void initOrResetVelocityTracker() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        } else {
            mVelocityTracker.clear();
        }
    }

    private void initVelocityTrackerIfNotExists() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
    }

    private void recycleVelocityTracker() {
        if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    private void checkIsClickHead(int downY, int headHeight, int scrollY) {
        isClickHead = downY + scrollY <= headHeight;
    }

    private void checkIsClickHeadExpand(int downY, int headHeight, int scrollY) {
        if (mExpandHeight <= 0) {
            isClickHeadExpand = false;
        }
        isClickHeadExpand = downY + scrollY <= headHeight + mExpandHeight;
    }

    private int calcDuration(int duration, int timepass) {
        return duration - timepass;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mHeadView = getChildAt(0);
        measureChildWithMargins(mHeadView, widthMeasureSpec, 0, MeasureSpec.UNSPECIFIED, 0);
        maxY = mHeadView.getMeasuredHeight();
        mHeadHeight = mHeadView.getMeasuredHeight();
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) + maxY, MeasureSpec.EXACTLY));
    }

    @Override
    protected void onFinishInflate() {
        if (mHeadView != null && !mHeadView.isClickable()) {
            mHeadView.setClickable(true);
        }
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childAt = getChildAt(i);
            if (childAt != null && childAt instanceof ViewPager) {
                childViewPager = (ViewPager) childAt;
            }
        }
        super.onFinishInflate();
    }
}


2.DetailFragment.java

计算ViewPager高度。

mCustomViewPager.getViewTreeObserver().addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        if (mCustomViewPager.getHeight() > 0)
                            mCustomViewPager.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        FlowLayout flow = null;
                        for (int i = 0; i < mCustomViewPager.getChildCount(); i++) {
                            flow = (FlowLayout) mCustomViewPager.getChildAt(i);
                            if (null != flow && mFlowLayoutHeight < (flow.getChildHeights() + flow.getTotalLines() * 14)) {
                                mFlowLayoutHeight = flow.getChildHeights() + flow.getTotalLines() * 14;
                                ViewGroup.LayoutParams lp = mCustomViewPager.getLayoutParams();
                                lp.height = LocalDisplay.dp2px(mFlowLayoutHeight);
                                mCustomViewPager.setLayoutParams(lp);
                            }
                        }
                    }
                });

标题栏滑动渐变

mScrollLayout.setOnScrollListener(new ScrollableLayout.OnScrollListener() {
            @Override
            public void onScroll(int currentY, int maxY) {
                ViewHelper.setTranslationY(mRlhead, (float) (currentY * 0.5));
                if (currentY <= 0) {
                    mTvBarTitle.setTextColor(Color.argb((int) 0, 66, 66, 66));//AGB由相关工具获得,或者美工提供或者美工提供
                    mLine.setBackgroundColor(Color.argb((int) 0, 217, 217, 217));
                    mTitleWholeArea.setBackgroundColor(Color.argb((int) 0, 251, 251, 251));
                } else if (currentY > 0 && currentY <= mHeight) {
                    float scale = (float) currentY / mHeight;
                    float alpha = (255 * scale);
                    // 只是layout背景透明(仿知乎滑动效果)
                    mTvBarTitle.setTextColor(Color.argb((int) alpha, 66, 66, 66));
                    mLine.setBackgroundColor(Color.argb((int) alpha, 217, 217, 217));
                    mTitleWholeArea.setBackgroundColor(Color.argb((int) alpha, 251, 251, 251));
                } else {
                    mTvBarTitle.setTextColor(Color.argb((int) 255, 66, 66, 66));
                    mLine.setBackgroundColor(Color.argb((int) 255, 217, 217, 217));
                    mTitleWholeArea.setBackgroundColor(Color.argb((int) 255, 251, 251, 251));
                }
            }
        });

布局文件如下

<com.xw.merchant.widget.scrollable.ScrollableLayout
        android:id="@+id/scrollableLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/ll_title_bar"
        android:orientation="vertical">

        <RelativeLayout
            android:id="@+id/rl_head"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/_white"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/tv_customer_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:layout_marginTop="@dimen/_gap_large"
                    android:text="黑手未入党"
                    android:textColor="@color/_color_gray5"
                    android:textSize="@dimen/_space_xxxlarge"
                    android:textStyle="bold" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/_space_small"
                    android:gravity="center"
                    android:orientation="horizontal">

                    <View
                        android:layout_width="@dimen/xw_gap_team_item_xxxlarge"
                        android:layout_height="@dimen/_line_thin"
                        android:layout_gravity="center"
                        android:layout_marginRight="@dimen/_gap_small"
                        android:background="@color/_textcolorHint" />

                    <TextView
                        android:id="@+id/tv_customer_mobile"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center"
                        android:gravity="center_horizontal"
                        android:text="18617080737"
                        android:textColor="@color/_color_gray5"
                        android:textSize="@dimen/_text_size_medium" />

                    <View
                        android:layout_width="@dimen/_gap_team_item_xxxlarge"
                        android:layout_height="@dimen/_line_thin"
                        android:layout_gravity="center"
                        android:layout_marginLeft="@dimen/_gap_small"
                        android:background="@color/_textcolorHint" />
                </LinearLayout>


                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/_space_small"
                    android:gravity="center"
                    android:orientation="horizontal">

                    <TextView
                        android:id="@+id/tv_my_customer_state"
                        android:layout_width="wrap_content"
                        android:layout_height="@dimen/_text_size_large"
                        android:background="@drawable/_sl_not_assign_customer"
                        android:gravity="center"
                        android:paddingLeft="@dimen/_space_small"
                        android:paddingRight="@dimen/_space_small"
                        android:text="@string/_consumption_un_assign"
                        android:textColor="@color/_white"
                        android:textSize="@dimen/_space_small_nine" />

                    <TextView
                        android:id="@+id/tv_staff_state"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="@dimen/_space_tiny"
                        android:gravity="center"
                        android:text="@string/_customer_distribution_status2"
                        android:textColor="@color/_color_yellow"
                        android:textSize="@dimen/_gap_small"
                        android:visibility="gone" />
                </LinearLayout>

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:layout_marginLeft="@dimen/_gap_team_item_xxxlarge"
                    android:layout_marginRight="@dimen/_gap_team_item_xxxlarge"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/tv_hd_empty"
                        android:layout_width="1dp"
                        android:layout_height="@dimen/_gap_medium"
                        android:background="@color/_white"
                        android:gravity="center"
                        android:visibility="invisible" />

                    <com.xw.merchant.widget.CustomViewPager
                        android:id="@+id/customViewPager"
                        android:layout_width="wrap_content"
                        android:layout_height="1dp"
                        android:gravity="center" />

                    <com.xw.merchant.widget.indicator.CirclePageIndicator
                        android:id="@+id/indicator"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_gravity="bottom"
                        android:visibility="gone"
                        app:fillColor="@color/_textcolor_assist"
                        app:pageColor="#32000000"
                        app:strokeWidth="0dp" />
                </LinearLayout>
            </LinearLayout>
        </RelativeLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/_white"
            android:gravity="center"
            android:orientation="horizontal"
            android:paddingBottom="@dimen/_xxxlarge"
            android:paddingTop="@dimen/_xxxlarge">

            <ImageView
                android:id="@+id/iv_btn_phone"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:src="@drawable/_phone" />

            <ImageView
                android:id="@+id/iv_btn_send_msg"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="@dimen/_xxxlarge"
                android:src="@drawable/_sms" />

            <ImageView
                android:id="@+id/iv_btn_upd"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="@dimen/_xxxlarge"
                android:src="@drawable/_upd" />

            <ImageView
                android:id="@+id/iv_btn_del"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="@dimen/_xxxlarge"
                android:src="@drawable/_del" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/tab_sliding_back"
            android:gravity="center">

            <com.xw.merchant.widget.scrollable.CustomPagerSlidingTabStrip
                android:id="@+id/pagerStrip"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_gravity="center_horizontal"
                android:background="@color/transparent"></com.xw.merchant.widget.scrollable.CustomPagerSlidingTabStrip>
        </LinearLayout>

        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </com.xw.merchant.widget.scrollable.ScrollableLayout>



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值