Android--仿1号店继续拖动查看图文详情——一个自定义的ViewGroup

      声明:源代码不是我写的,是网上的以为大神写的(地址给忘了),我拿过来以后呢,稍微改动了一下源码,使之符合了项目需求,再次特别感谢那位大牛,非常感谢。

是一个自定义布局,继承自ViewGroup

package com.storelibrary.ui.custom.widget;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import newair.com.storelibrary.R;
import newair.com.storelibrary.utils.L;

/**
 * ----仿京东、淘宝、一号店商品详情上拉显示图文详情------
 */
@SuppressWarnings("unused")
public class SlideDetailsLayout extends ViewGroup {


    public static final String TAG = "slide";
    public static final boolean DEBUG = true;


    public boolean isTop = true;

    /**
     * Callback for panel OPEN-CLOSE status changed.
     */
    public interface OnSlideDetailsListener {
        /**
         * Called after status changed.
         *
         * @param status {@link Status}
         */
        void onStatusChanged(Status status);
    }

    public enum Status {
        /**
         * Panel is closed
         */
        CLOSE,
        /**
         * Panel is opened
         */
        OPEN;

        public static Status valueOf(int stats) {
            if (0 == stats) {
                return CLOSE;
            } else if (1 == stats) {
                return OPEN;
            } else {
                return CLOSE;
            }
        }
    }

    private static final float DEFAULT_PERCENT = 0.2f;
    private static final int DEFAULT_DURATION = 200;

    private View mFrontView;
    private View mBehindView;

    private float mTouchSlop;
    private float mInitMotionY;
    private float mInitMotionX;


    private View mTarget;
    private float mSlideOffset;
    private Status mStatus = Status.CLOSE;
    private boolean isFirstShowBehindView = true;
    private float mPercent = DEFAULT_PERCENT;
    private long mDuration = DEFAULT_DURATION;
    private int mDefaultPanel = 0;

    private OnSlideDetailsListener mOnSlideDetailsListener;

    public SlideDetailsLayout(Context context) {
        this(context, null);
    }

    public SlideDetailsLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlideDetailsLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlideDetailsLayout, defStyleAttr, 0);
        mPercent = a.getFloat(R.styleable.SlideDetailsLayout_percent, DEFAULT_PERCENT);
        mDuration = a.getInt(R.styleable.SlideDetailsLayout_duration, DEFAULT_DURATION);
        mDefaultPanel = a.getInt(R.styleable.SlideDetailsLayout_default_panel, 0);
        a.recycle();

        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
    }

    /**
     * Set the callback of panel OPEN-CLOSE status.
     *
     * @param listener {@link OnSlideDetailsListener}
     */
    public void setOnSlideDetailsListener(OnSlideDetailsListener listener) {
        this.mOnSlideDetailsListener = listener;
    }

    /**
     * Open pannel smoothly.
     *
     * @param smooth true, smoothly. false otherwise.
     */
    public void smoothOpen(boolean smooth) {
        if (mStatus != Status.OPEN) {
            mStatus = Status.OPEN;
            final float height = -getMeasuredHeight();
            animatorSwitch(0, height, true, smooth ? mDuration : 0);
        }
    }

    /**
     * Close pannel smoothly.
     *
     * @param smooth true, smoothly. false otherwise.
     */
    public void smoothClose(boolean smooth) {
        if (mStatus != Status.CLOSE) {
            mStatus = Status.OPEN;
            final float height = -getMeasuredHeight();
            animatorSwitch(height, 0, true, smooth ? mDuration : 0);
        }
    }

    /**
     * Set the float value for indicate the moment of switch panel
     *
     * @param percent (0.0, 1.0)
     */
    public void setPercent(float percent) {
        this.mPercent = percent;
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return new MarginLayoutParams(p);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        final int childCount = getChildCount();
        if (1 >= childCount) {
            throw new RuntimeException("SlideDetailsLayout only accept childs more than 1!!");
        }

        mFrontView = getChildAt(0);
        mBehindView = getChildAt(1);

        // set behindview's visibility to GONE before show.
//        mBehindView.setVisibility(GONE);
        if (mDefaultPanel == 1) {
            post(new Runnable() {
                @Override
                public void run() {
                    smoothOpen(false);
                }
            });
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int pWidth = MeasureSpec.getSize(widthMeasureSpec);
        final int pHeight = MeasureSpec.getSize(heightMeasureSpec);

        final int childWidthMeasureSpec =
                MeasureSpec.makeMeasureSpec(pWidth, MeasureSpec.EXACTLY);
        final int childHeightMeasureSpec =
                MeasureSpec.makeMeasureSpec(pHeight, MeasureSpec.EXACTLY);

        View child;
        for (int i = 0; i < getChildCount(); i++) {
            child = getChildAt(i);
            // skip measure if gone
            if (child.getVisibility() == GONE) {
                continue;
            }

            measureChild(child, childWidthMeasureSpec, childHeightMeasureSpec);
        }

        setMeasuredDimension(pWidth, pHeight);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int left = l;
        final int right = r;
        int top;
        int bottom;

        final int offset = (int) mSlideOffset;

        View child;
        for (int i = 0; i < getChildCount(); i++) {
            child = getChildAt(i);

            // skip layout
            if (child.getVisibility() == GONE) {
                continue;
            }

            if (child == mBehindView) {
                top = b + offset;
                bottom = top + b - t;
            } else {
                top = t + offset;
                bottom = b + offset;
            }

            child.layout(left, top, right, bottom);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        ensureTarget();
        if (null == mTarget) {
            return false;
        }

        if (!isEnabled()) {
            return false;
        }

        final int aciton = MotionEventCompat.getActionMasked(ev);

        boolean shouldIntercept = false;
        switch (aciton) {
            case MotionEvent.ACTION_DOWN: {
                mInitMotionX = ev.getX();
                mInitMotionY = ev.getY();
                shouldIntercept = false;
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                final float x = ev.getX();
                final float y = ev.getY();

                final float xDiff = x - mInitMotionX;
                final float yDiff = y - mInitMotionY;

                if (canChildScrollVertically((int) yDiff)) {
                    shouldIntercept = false;
                    if (DEBUG) {
                        Log.d(TAG, "intercept, child can scroll vertically, do not intercept");
                    }
                } else {
                    final float xDiffabs = Math.abs(xDiff);
                    final float yDiffabs = Math.abs(yDiff);

                    // intercept rules:
                    // 1. The vertical displacement is larger than the horizontal displacement;
                    // 2. Panel stauts is CLOSE:slide up
                    // 3. Panel status is OPEN:slide down
                    if (yDiffabs > mTouchSlop && yDiffabs >= xDiffabs
                            && !(mStatus == Status.CLOSE && yDiff > 0
                            || mStatus == Status.OPEN && yDiff < 0)) {
                        shouldIntercept = true;
                        if (DEBUG) {
                            Log.d(TAG, "intercept, intercept events");
                        }
                    }
                }
                break;
            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                shouldIntercept = false;
                break;
            }

        }

        return shouldIntercept;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        ensureTarget();
        if (null == mTarget) {
            return false;
        }

        if (!isEnabled()) {
            return false;
        }

        boolean wantTouch = true;
        final int action = MotionEventCompat.getActionMasked(ev);

        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                // if target is a view, we want the DOWN action.
                if (mTarget instanceof View) {
                    wantTouch = true;
                }
                break;
            }

            case MotionEvent.ACTION_MOVE: {
                final float y = ev.getY();
                final float yDiff = y - mInitMotionY;
                if (canChildScrollVertically(((int) yDiff))) {
                    wantTouch = false;
                } else {
                    processTouchEvent(yDiff);
                    wantTouch = true;
                }
                break;
            }

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                finishTouchEvent();
                wantTouch = false;
                break;
            }
        }
        return wantTouch;
    }

    /**
     * @param offset Displacement in vertically.
     */
    private void processTouchEvent(final float offset) {
        if (Math.abs(offset) < mTouchSlop) {
            return;
        }

        final float oldOffset = mSlideOffset;

        // pull up to open
        if (mStatus == Status.CLOSE) {
            // reset if pull down
            if (offset >= 0) {
                mSlideOffset = 0;
            } else {
                mSlideOffset = offset;
            }

            if (mSlideOffset == oldOffset) {
                return;
            }

            // pull down to close
        } else if (mStatus == Status.OPEN) {
            final float pHeight = -getMeasuredHeight();
            // reset if pull up
            if (offset <= 0) {
                mSlideOffset = pHeight;
            } else {
                final float newOffset = pHeight + offset;
                mSlideOffset = newOffset;
            }

            if (mSlideOffset == oldOffset) {
                return;
            }
        }

        if (DEBUG) {
            Log.v("slide", "process, offset: " + mSlideOffset);
        }
        // relayout
        requestLayout();
    }

    /**
     * Called after gesture is ending.
     */
    private void finishTouchEvent() {
        final int pHeight = getMeasuredHeight();
//        final int percent = (int) (pHeight * mPercent);
        final int percent = 200;
        final float offset = mSlideOffset;

        if (DEBUG) {
            Log.d("slide", "finish, offset: " + offset + ", percent: " + percent);
        }

        boolean changed = false;

        if (Status.CLOSE == mStatus) {
            if (offset <= -percent) {
                mSlideOffset = -pHeight;
                mStatus = Status.OPEN;
                changed = true;
            } else {
                // keep panel closed
                mSlideOffset = 0;
            }
        } else if (Status.OPEN == mStatus) {
            if ((offset + pHeight) >= percent) {
                mSlideOffset = 0;
                mStatus = Status.CLOSE;
                changed = true;
            } else {
                // keep panel opened
                mSlideOffset = -pHeight;
            }
        }

        animatorSwitch(offset, mSlideOffset, changed);
    }

    private void animatorSwitch(final float start, final float end) {
        animatorSwitch(start, end, true, mDuration);
    }

    private void animatorSwitch(final float start, final float end, final long duration) {
        animatorSwitch(start, end, true, duration);
    }

    private void animatorSwitch(final float start, final float end, final boolean changed) {
        animatorSwitch(start, end, changed, mDuration);
    }

    private void animatorSwitch(final float start,
                                final float end,
                                final boolean changed,
                                final long duration) {
        ValueAnimator animator = ValueAnimator.ofFloat(start, end);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mSlideOffset = (float) animation.getAnimatedValue();
                requestLayout();
            }
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (changed) {
                    if (mStatus == Status.OPEN) {
                        checkAndFirstOpenPanel();
                    }

                    if (null != mOnSlideDetailsListener) {
                        mOnSlideDetailsListener.onStatusChanged(mStatus);
                    }
                }
            }
        });
        animator.setDuration(duration);
        animator.start();
    }

    /**
     * Whether the closed pannel is opened at first time.
     * If open first, we should set the behind view's visibility as VISIBLE.
     */
    private void checkAndFirstOpenPanel() {
        if (isFirstShowBehindView) {
            isFirstShowBehindView = false;
            mBehindView.setVisibility(VISIBLE);
        }
    }

    /**
     * When pulling, target view changed by the panel status. If panel opened, the target is behind view.
     * Front view is for otherwise.
     */
    private void ensureTarget() {
        if (mStatus == Status.CLOSE) {
            mTarget = mFrontView;
        } else {
            mTarget = mBehindView;
        }
    }

    //ViewPager的当前所在位置
    public int viewPagerCurrent = 0;

    public int getViewPagerCurrent() {
        return viewPagerCurrent;
    }

    public void setViewPagerCurrent(int viewPagerCurrent) {
        this.viewPagerCurrent = viewPagerCurrent;
    }

    /**
     * Check child view can srcollable in vertical direction.
     *
     * @param direction Negative to check scrolling up, positive to check scrolling down.
     * @return true if this view can be scrolled in the specified direction, false otherwise.
     */
    protected boolean canChildScrollVertically(int direction) {
        if (mTarget instanceof AbsListView) {
            return canListViewSroll((AbsListView) mTarget);
        } else if (mTarget instanceof FrameLayout ||
                mTarget instanceof RelativeLayout ||
                mTarget instanceof LinearLayout) {
            View child;
            for (int i = 0; i < ((ViewGroup) mTarget).getChildCount(); i++) {
                child = ((ViewGroup) mTarget).getChildAt(i);
                if (child instanceof AbsListView) {
                    return canListViewSroll((AbsListView) child);
                } else if (child instanceof ScrollView) {
                    return canScrollViewSroll((ScrollView) child);
                } else if (child instanceof ViewPager) {
                    ViewPager pager = (ViewPager) child;
                    View child2 = pager.getChildAt(viewPagerCurrent);
                    if (child2 instanceof RecyclerView) {
                        return canRecyclerViewSroll((RecyclerView) child2);
                    } else if (child2 instanceof ScrollView) {
                        return canScrollViewSroll((ScrollView) child2);
                    }
                }
            }
        }

        if (android.os.Build.VERSION.SDK_INT < 14)

        {
            return ViewCompat.canScrollVertically(mTarget, -direction) || mTarget.getScrollY() > 0;
        } else

        {
            return ViewCompat.canScrollVertically(mTarget, -direction);
        }
    }

    protected boolean canListViewSroll(AbsListView absListView) {
        if (mStatus == Status.OPEN) {
            return absListView.getChildCount() > 0
                    && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
                    .getTop() <
                    absListView.getPaddingTop());
        } else {
            final int count = absListView.getChildCount();
            return count > 0
                    && (absListView.getLastVisiblePosition() < count - 1
                    || absListView.getChildAt(count - 1)
                    .getBottom() > absListView.getMeasuredHeight());
        }
    }

    protected boolean canRecyclerViewSroll(RecyclerView absListView) {
        if (mStatus == Status.OPEN) {
            L.i(absListView.getScrollY() + ":scaleY" + "	");

            return absListView.getChildCount() > 0
                    && (absListView.getScrollY() > 0 || absListView.getChildAt(0)
                    .getTop() <
                    absListView.getPaddingTop());
        } else {
            final int count = absListView.getChildCount();
            return count > 0
                    && (absListView.getScrollY() <= count - 1
                    || absListView.getChildAt(count - 1)
                    .getBottom() > absListView.getMeasuredHeight());
        }
    }

    protected boolean canScrollViewSroll(ScrollView absListView) {
        if (mStatus == Status.OPEN) {
            L.i(absListView.getScrollY() + ":scaleY" + "	" + absListView.getChildAt(0)
                    .getTop() + "=== " + absListView.getPaddingTop());

            return absListView.getChildCount() > 0
                    && (absListView.getScrollY() > 0 || absListView.getChildAt(0)
                    .getTop() <
                    absListView.getPaddingTop());
        } else {
            final int count = absListView.getChildCount();
            return count > 0
                    && (absListView.getScrollY() <= count - 1
                    || absListView.getChildAt(count - 1)
                    .getBottom() > absListView.getMeasuredHeight());
        }
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        SavedState ss = new SavedState(super.onSaveInstanceState());
        ss.offset = mSlideOffset;
        ss.status = mStatus.ordinal();
        return ss;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());
        mSlideOffset = ss.offset;
        mStatus = Status.valueOf(ss.status);

        if (mStatus == Status.OPEN) {
            mBehindView.setVisibility(VISIBLE);
        }

        requestLayout();
    }

    static class SavedState extends BaseSavedState {

        private float offset;
        private int status;

        /**
         * Constructor used when reading from a parcel. Reads the state of the superclass.
         *
         * @param source
         */
        public SavedState(Parcel source) {
            super(source);
            offset = source.readFloat();
            status = source.readInt();
        }

        /**
         * Constructor called by derived classes when creating their SavedState objects
         *
         * @param superState The state of the superclass of this view
         */
        public SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeFloat(offset);
            out.writeInt(status);
        }

        public static final Creator<SavedState> CREATOR =
                new Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }

                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
    }
}

2、这个自定义布局使用起来也非常的方便---还是代码直接点

  这里面能放两个Viewgroup,第二个Viewgroup就是拖出来的viewgroup--下面的界面是直接仿照的一号店的

<com.storelibrary.ui.custom.widget.SlideDetailsLayout
        android:id="@+id/SlideDetailsLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/ll_bottom_layout">

        <ScrollView
            android:id="@+id/sl_top_details"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@+id/ll_bottom_layout"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:gravity="center"
            android:scrollbars="none">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                    <android.support.v4.view.ViewPager
                        android:id="@+id/vp_goods_details"
                        android:layout_width="match_parent"
                        android:layout_height="300dp"
                        android:visibility="visible" />

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentBottom="true"
                        android:layout_alignParentEnd="true"
                        android:layout_alignParentRight="true"
                        android:orientation="horizontal"
                        android:padding="10dp">

                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:clickable="true"
                            android:src="@drawable/good_details_collection" />

                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginLeft="10dp"
                            android:clickable="true"
                            android:src="@drawable/good_details_share" />
                    </LinearLayout>
                </RelativeLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="0.5dp"
                    android:background="#d9d9d9" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:padding="10dp">

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:background="@drawable/item_good_details_icon_style"
                            android:text="自营"
                            android:textColor="#ef4c4c"
                            android:textSize="12sp" />

                        <TextView
                            android:id="@+id/tv_goods_name"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginLeft="5dp"
                            android:text="沙宣 修复水养 洗发露 750ml" />
                    </LinearLayout>

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="5dp"
                        android:hint="水感润养,发型丰盈可塑"
                        android:textSize="12sp" />

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="5dp"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <TextView
                            android:id="@+id/tv_goods_price"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="¥58.9"
                            android:textColor="#f23333" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginLeft="5dp"
                            android:background="#e49a39"
                            android:paddingLeft="2dp"
                            android:paddingRight="2dp"
                            android:text="比PC省¥1.0"
                            android:textColor="#fff"
                            android:textSize="12sp" />

                    </LinearLayout>

                </LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="0.5dp"
                    android:background="#dcdbdb" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:padding="10dp">


                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_vertical"
                        android:orientation="vertical">

                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:gravity="center_vertical"
                            android:orientation="horizontal">

                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_gravity="center_vertical"
                                android:text="选择" />

                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_marginLeft="10dp"
                                android:layout_weight="1"
                                android:gravity="center_vertical"
                                android:text="选择规格"
                                android:textColor="#1b1b1b"
                                android:textSize="12sp" />

                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:src="@drawable/good_details_arrows_right" />
                        </LinearLayout>

                    </LinearLayout>

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="10dp"
                        android:orientation="horizontal">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="送至" />

                        <LinearLayout
                            android:layout_width="match_parent"
                            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="#202020" />

                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_marginTop="5dp"
                                android:hint="现货,12:00前完成订单,预计1天内到达" />

                            <View
                                android:layout_width="match_parent"
                                android:layout_height="0.5dp"
                                android:layout_marginTop="10dp"
                                android:background="#dedede" />
                        </LinearLayout>

                    </LinearLayout>

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_vertical"
                        android:layout_marginTop="10dp"
                        android:orientation="horizontal">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="服务" />

                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            android:layout_marginLeft="10dp"
                            android:gravity="center_vertical"
                            android:orientation="horizontal">

                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:hint="支持货到付款"
                                android:textSize="12sp" />

                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_marginLeft="10dp"
                                android:hint="1贵就赔"
                                android:textSize="12sp" />
                        </LinearLayout>

                    </LinearLayout>

                </LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="10dp"
                    android:background="#e1e1e1" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:padding="10dp">

                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="商品评价 (44804)"
                            android:textColor="#393939" />

                        <LinearLayout
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignParentEnd="true"
                            android:layout_alignParentRight="true"
                            android:gravity="center_vertical">

                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:text="97%"
                                android:textColor="#f14d4d" />

                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:drawableRight="@drawable/good_details_arrows_right"
                                android:gravity="center_vertical"
                                android:text="好评" />
                        </LinearLayout>
                    </RelativeLayout>

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="评分" />

                        <RatingBar
                            style="@android:style/Widget.Holo.RatingBar.Small"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content" />
                    </LinearLayout>

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="10dp"
                        android:hint="还可以,不错不错"
                        android:textSize="12sp" />
                </LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="10dp"
                    android:background="#e1e1e1" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="40dp"
                        android:paddingLeft="10dp"
                        android:paddingRight="10dp">

                        <ImageView
                            android:id="@+id/iv_search_icon"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_centerVertical="true"
                            android:src="@drawable/ic_skip_next_black_36dp" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_centerVertical="true"
                            android:layout_marginLeft="20dp"
                            android:layout_toRightOf="@+id/iv_search_icon"
                            android:text="VS/沙宣" />

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignParentRight="true"
                            android:layout_centerVertical="true"
                            android:text="搜索" />
                    </RelativeLayout>

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="0.5dp"
                        android:layout_marginLeft="10dp"
                        android:layout_marginRight="10dp"
                        android:background="#e2e2e2" />

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="40dp"
                        android:gravity="center"
                        android:paddingLeft="10dp"
                        android:paddingRight="10dp">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="联系客服" />
                    </LinearLayout>
                </LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="10dp"
                    android:background="#e1e1e1" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:padding="10dp">

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:hint="买的人还会买" />

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="0.5dp"
                        android:layout_marginTop="10dp"
                        android:background="#dfdfdf" />

                    <android.support.v7.widget.RecyclerView
                        android:id="@+id/rv_recommend_goodsDetails"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:focusable="false"
                        android:focusableInTouchMode="false" />

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="0.5dp"
                        android:background="#dfdfdf" />
                </LinearLayout>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="45dp"
                    android:background="#e7e7e7"
                    android:gravity="center"
                    android:orientation="horizontal">

                    <ImageView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:src="@drawable/goods_details_look_more" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="继续拖动查看图文详情" />
                </LinearLayout>
            </LinearLayout>

        </ScrollView>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <android.support.design.widget.TabLayout
                android:id="@+id/tl"
                android:layout_width="match_parent"
                android:layout_height="45dp"
                app:tabGravity="fill"
                app:tabIndicatorColor="@android:color/holo_red_light"
                app:tabIndicatorHeight="3dp"
                app:tabSelectedTextColor="@android:color/black"
                app:tabTextColor="@android:color/darker_gray" />

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

        </LinearLayout>

    </com.storelibrary.ui.custom.widget.SlideDetailsLayout>

3、如何使用呢---很方便

  ①、先介绍第一个,他有一个打开还是关闭的监听    

slideDetailsLayout = (SlideDetailsLayout) findViewById(R.id.SlideDetailsLayout);
        slideDetailsLayout.setOnSlideDetailsListener(new SlideDetailsLayout.OnSlideDetailsListener() {
            @Override
            public void onStatusChanged(SlideDetailsLayout.Status status) {
                switch (status) {
                    case CLOSE://关闭了
                        
                        break;
                    case OPEN://打开了
                        
                        break;
                }
            }
        });

②、如果拖拽出来的布局里面放着TabLaoout和viewpager的,别忘了下面的代码

List<View> myData = new ArrayList<>();
View pager_1 = View.inflate(this, R.layout.pager_goods_details_1, null);
View pager_2 = View.inflate(this, R.layout.pager_goods_details_2, null);
View pager_3 = View.inflate(this, R.layout.pager_goods_details_3, null);
myData.add(pager_1);
myData.add(pager_2);
myData.add(pager_3);
//数据源放三个Layout,(感觉这样不好,放三个fragment应该不错,我没试过会不会出现问题,小伙伴们可以试一试)
myGoodsDetailsVPAdapter = new MyGoodsDetailsVPAdapter(this, myData);
 tl = (TabLayout) findViewById(R.id.tl);
        vp = (ViewPager) findViewById(R.id.vp);

        vp.setOffscreenPageLimit(3);//设置viewpager的强制缓存为3个(这里的话,是几个就设置为缓存几个,否则会由于viewPager缓存的问题,导致拖拽出来的布局无法滑动)
        vp.setAdapter(myGoodsDetailsVPAdapter);
        tl.setupWithViewPager(vp);
        tl.setTabsFromPagerAdapter(myGoodsDetailsVPAdapter);


        tl.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                vp.setCurrentItem(tab.getPosition());
                slideDetailsLayout.setViewPagerCurrent(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
原文地址:https://www.cnblogs.com/819158327fan/p/5442304.html