1. 程式人生 > >Android開發仿淘寶商品詳情瀏覽效果 兩步曲

Android開發仿淘寶商品詳情瀏覽效果 兩步曲

效果圖:

第一步佈局檔案:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/containerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:orientation="vertical">
    <!--父容器-->
    <com.little.monkey.myapplication.ScrollViewContainer
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/bottom"
        android:layout_below="@+id/lintonei"
        android:layout_marginBottom="-27dp">

        <!--商品詳情-->
        <ScrollView
            android:id="@+id/mymyscrollview"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="#ffffff"
            android:scrollbars="none">

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

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

                    <ImageView
                        android:id="@+id/detial_product_img"
                        android:layout_width="match_parent"
                        android:layout_height="500dp"
                        android:background="@mipmap/ic_launcher_round"
                        android:scaleType="fitXY" />
                    
                </RelativeLayout>

                <View
                    android:layout_width="fill_parent"
                    android:layout_height="1dp"
                    android:background="#f3f2f8" />

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="127dp"
                    android:background="#ffffff">

                    <RelativeLayout
                        android:id="@+id/layout_1"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical">

                        <TextView
                            android:id="@+id/detial_product_name"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginLeft="12dp"
                            android:layout_marginTop="17dp"
                            android:ellipsize="end"
                            android:lines="2"
                            android:maxLines="2"
                            android:text="暫無商品 "
                            android:textColor="#262626"
                            android:textSize="16dp" />

                        <TextView
                            android:id="@+id/detial_product_num"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_below="@+id/detial_product_name"
                            android:layout_marginLeft="12dp"
                            android:layout_marginTop="6dp"
                            android:text="已售00件"
                            android:textColor="#999999"
                            android:textSize="12dp" />

                        <RelativeLayout
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignParentBottom="true"
                            android:layout_alignParentRight="true"
                            android:layout_marginBottom="15dp"
                            android:layout_marginRight="17dp">

                            <TextView
                                android:id="@+id/textjrgwc"
                                android:layout_width="105dp"
                                android:layout_height="33dp"
                                android:background="@color/colorPrimary"
                                android:gravity="center"
                                android:text="加入購物車"
                                android:textColor="#ffffff"
                                android:textSize="14dp"
                                android:visibility="gone" />

                            <LinearLayout
                                android:id="@+id/linearjjgwc"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content">

                                <TextView
                                    android:id="@+id/tvMinus"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:background="@mipmap/ic_launcher_round"
                                    android:clickable="true"
                                    android:gravity="center" />

                                <TextView
                                    android:id="@+id/count"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:layout_gravity="center_vertical"
                                    android:layout_marginBottom="3dp"
                                    android:layout_marginLeft="5dp"
                                    android:layout_marginRight="5dp"
                                    android:gravity="center"
                                    android:text="0"
                                    android:textColor="#1a1a1a"
                                    android:textSize="18dp" />

                                <TextView
                                    android:id="@+id/tvAdd"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:layout_marginBottom="7dp"
                                    android:background="@mipmap/ic_launcher_round"
                                    android:clickable="true"
                                    android:gravity="center" />
                            </LinearLayout>
                        </RelativeLayout>


                        <TextView
                            android:id="@+id/detial_product_price"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_below="@+id/detial_product_num"
                            android:layout_marginLeft="12dp"
                            android:layout_marginTop="15dp"
                            android:text="¥0.00"
                            android:textColor="#f33637"
                            android:textSize="18dp"
                            android:textStyle="bold" />

                        <TextView
                            android:id="@+id/textyuanjia"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_below="@+id/detial_product_num"
                            android:layout_marginLeft="12dp"
                            android:layout_marginTop="19dp"
                            android:layout_toRightOf="@+id/detial_product_price"
                            android:text="原價:"
                            android:textSize="12dp" />

                        <TextView
                            android:id="@+id/zhejia"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_below="@+id/detial_product_num"
                            android:layout_marginTop="19dp"
                            android:layout_toRightOf="@+id/textyuanjia"
                            android:text="¥0.00"
                            android:textSize="12dp" />
                    </RelativeLayout>


                </RelativeLayout>

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

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="140dp"
                    android:visibility="gone">

                    <TextView
                        android:id="@+id/textspgg"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="12dp"
                        android:layout_marginTop="16dp"
                        android:textColor="#676767"
                        android:textSize="14dp" />

                </RelativeLayout>

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="110dp"
                    android:visibility="gone">

                    <TextView
                        android:id="@+id/textname"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="12dp"
                        android:layout_marginTop="21dp"
                        android:textColor="#262626"
                        android:textSize="14dp" />

                    <TextView
                        android:id="@+id/textdz"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_below="@+id/textname"
                        android:layout_marginLeft="12dp"
                        android:layout_marginTop="12dp"
                        android:maxLength="20"
                        android:textColor="#989898"
                        android:textSize="13dp" />

                    <RelativeLayout
                        android:id="@+id/relativedh"
                        android:layout_width="64dp"
                        android:layout_height="37dp"
                        android:layout_alignParentRight="true"
                        android:layout_below="@+id/textname">

                        <TextView
                            android:layout_width="1dp"
                            android:layout_height="fill_parent"
                            android:background="#d8d8d8" />

                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_centerHorizontal="true"
                            android:layout_centerVertical="true"
                            android:src="@mipmap/ic_launcher_round" />
                    </RelativeLayout>

                    <ImageView
                        android:id="@+id/imagdw"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_below="@+id/textdz"
                        android:layout_marginLeft="10dp"
                        android:layout_marginTop="11dp"
                        android:src="@mipmap/ic_launcher_round" />

                    <TextView
                        android:id="@+id/textmishu"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_below="@+id/textdz"
                        android:layout_marginLeft="5dp"
                        android:layout_marginTop="12dp"
                        android:layout_toRightOf="@+id/imagdw"
                        android:textColor="#999999"
                        android:textSize="13dp" />
                </RelativeLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="9dp"
                    android:background="#f2f2f2" />

                <RelativeLayout
                    android:id="@+id/linearpl"
                    android:layout_width="fill_parent"
                    android:layout_height="50dp"
                    android:orientation="vertical">

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerVertical="true"
                        android:layout_marginLeft="15dp"
                        android:text="商品評價"
                        android:textColor="#303030"
                        android:textSize="15dp" />

                    <TextView
                        android:id="@+id/textsong_id"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerVertical="true"
                        android:layout_marginRight="15dp"
                        android:layout_toLeftOf="@+id/xiangyou2_id"
                        android:text="全部評價"
                        android:textColor="#999999"
                        android:textSize="12dp" />

                    <ImageView
                        android:id="@+id/xiangyou2_id"
                        android:layout_width="15dp"
                        android:layout_height="15dp"
                        android:layout_alignParentRight="true"
                        android:layout_centerVertical="true"
                        android:layout_marginRight="13dp"
                        android:src="@mipmap/ic_launcher_round" />

                    <Button
                        android:id="@+id/chakangengduo"
                        android:layout_width="wrap_content"
                        android:layout_height="25dp"
                        android:layout_centerHorizontal="true"
                        android:layout_centerVertical="true"
                        android:background="@color/colorPrimaryDark"
                        android:text="檢視全部評價"
                        android:textColor="#CDCDCD"
                        android:textSize="12sp"
                        android:visibility="gone" />
                </RelativeLayout>


                <View
                    android:layout_width="match_parent"
                    android:layout_height="9dp"
                    android:background="#f2f2f2" />


                <RelativeLayout
                    android:layout_width="fill_parent"
                    android:layout_height="50dp"
                    android:orientation="vertical">

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerVertical="true"
                        android:layout_marginLeft="15dp"
                        android:text="商品詳情"
                        android:textColor="#303030"
                        android:textSize="15dp" />

                    <ImageView
                        android:layout_width="15dp"
                        android:layout_height="15dp"
                        android:layout_alignParentRight="true"
                        android:layout_centerVertical="true"
                        android:layout_marginRight="13dp"
                        android:src="@mipmap/ic_launcher_round" />

                </RelativeLayout>

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

                <LinearLayout
                    android:layout_width="fill_parent"
                    android:layout_height="90dp"
                    android:background="#ffffff">

                    <TextView
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent"
                        android:layout_marginTop="20dp"
                        android:gravity="center_horizontal"
                        android:text="上滑檢視圖文詳情"
                        android:textColor="#989898"
                        android:textSize="14dp" />
                </LinearLayout>

            </LinearLayout>
        </ScrollView>
        <!--圖文詳情-->
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="-50dp"
            android:background="#f78ddd">

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

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

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

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

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="asdfasdfas" />
            </LinearLayout>
        </ScrollView>
    </com.little.monkey.myapplication.ScrollViewContainer>


    <!--標題欄-->
    <LinearLayout
        android:id="@+id/lintonei"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <RelativeLayout
            android:id="@+id/title_layout_product"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:background="#fff">

            <ImageView
                android:id="@+id/iv_title_left"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:padding="3dp"
                android:src="@mipmap/ic_launcher_round" />

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_centerInParent="true"
                android:gravity="center"
                android:text="商品詳情"
                android:textColor="@color/colorAccent"
                android:textSize="18sp" />

        </RelativeLayout>

        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:background="#d9d9d9" />
    </LinearLayout>
    <!--底部購物車-->
    <RelativeLayout
        android:id="@+id/bottom"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:background="#3b3b38"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tvCost"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="89dp"
            android:text="¥ 0.0"
            android:textColor="#fff"
            android:textSize="16dp" />

        <TextView
            android:id="@+id/tvSubmit"
            android:layout_width="130dp"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
            android:background="#4a4a47"
            android:gravity="center"
            android:text="去結算"
            android:textColor="#fff"
            android:textSize="16dp" />

    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/relative_gwc"
        android:layout_width="89dp"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="10dp">

        <ImageView
            android:id="@+id/imgCart"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/ic_launcher_round" />

        <TextView
            android:id="@+id/tvount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_marginRight="13dp"
            android:background="@color/colorAccent"
            android:gravity="center"
            android:text="0"
            android:textColor="#fff"
            android:textSize="12sp"
            android:visibility="gone" />
    </RelativeLayout>

</RelativeLayout>

第二步封裝一個父容器ScrollViewContainer:

package com.little.monkey.myapplication;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.ScrollView;

import java.util.Timer;
import java.util.TimerTask;
/**
 * Created by Administrator on 2018/9/13 0013.
 */

public class ScrollViewContainer extends RelativeLayout{
    /**
     * 自動上滑
     */
    public static final int AUTO_UP = 0;
    /**
     * 自動下滑
     */
    public static final int AUTO_DOWN = 1;
    /**
     * 動畫完成
     */
    public static final int DONE = 2;
    /**
     * 動畫速度
     */
    public static final float SPEED = 6.5f;

    private boolean isMeasured = false;

    /**
     * 用於計算手滑動的速度
     */
    private VelocityTracker vt;

    private int mViewHeight;
    private int mViewWidth;

    private View topView;
    private View bottomView;

    private boolean canPullDown;
    private boolean canPullUp;
    private int state = DONE;

    /**
     * 記錄當前展示的是哪個view,0是topView,1是bottomView
     */
    private int mCurrentViewIndex = 0;
    /**
     * 手滑動距離,這個是控制佈局的主要變數
     */
    private float mMoveLen;
    private MyTimer mTimer;
    private float mLastY;
    /**
     * 用於控制是否變動佈局的另一個條件,mEvents==0時佈局可以拖拽了,mEvents==-1時可以捨棄將要到來的第一個move事件,
     * 這點是去除多點拖動劇變的關鍵
     */
    private int mEvents;

    private Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            if (mMoveLen != 0) {
                if (state == AUTO_UP) {
                    mMoveLen -= SPEED;
                    if (mMoveLen <= -mViewHeight) {
                        mMoveLen = -mViewHeight;
                        state = DONE;
                        mCurrentViewIndex = 1;
                    }
                } else if (state == AUTO_DOWN) {
                    mMoveLen += SPEED;
                    if (mMoveLen >= 0) {
                        mMoveLen = 0;
                        state = DONE;
                        mCurrentViewIndex = 0;
                    }
                } else {
                    mTimer.cancel();
                }
            }
            requestLayout();
        }

    };

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

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

    public ScrollViewContainer(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        mTimer = new MyTimer(handler);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                if (vt == null)
                    vt = VelocityTracker.obtain();
                else
                    vt.clear();
                mLastY = ev.getY();
                vt.addMovement(ev);
                mEvents = 0;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
            case MotionEvent.ACTION_POINTER_UP:
                // 多一隻手指按下或擡起時捨棄將要到來的第一個事件move,防止多點拖拽的bug
                mEvents = -1;
                break;
            case MotionEvent.ACTION_MOVE:
                vt.addMovement(ev);
                if (canPullUp && mCurrentViewIndex == 0 && mEvents == 0) {
                    mMoveLen += (ev.getY() - mLastY);
                    // 防止上下越界
                    if (mMoveLen > 0) {
                        mMoveLen = 0;
                        mCurrentViewIndex = 0;
                    } else if (mMoveLen < -mViewHeight) {
                        mMoveLen = -mViewHeight;
                        mCurrentViewIndex = 1;

                    }
                    if (mMoveLen < -8) {
                        // 防止事件衝突
                        ev.setAction(MotionEvent.ACTION_CANCEL);
                    }
                } else if (canPullDown && mCurrentViewIndex == 1 && mEvents == 0) {
                    mMoveLen += (ev.getY() - mLastY);
                    // 防止上下越界
                    if (mMoveLen < -mViewHeight) {
                        mMoveLen = -mViewHeight;
                        mCurrentViewIndex = 1;
                    } else if (mMoveLen > 0) {
                        mMoveLen = 0;
                        mCurrentViewIndex = 0;
                    }
                    if (mMoveLen > 8 - mViewHeight) {
                        // 防止事件衝突
                        ev.setAction(MotionEvent.ACTION_CANCEL);
                    }
                } else
                    mEvents++;
                mLastY = ev.getY();
                requestLayout();
                break;
            case MotionEvent.ACTION_UP:
                mLastY = ev.getY();
                vt.addMovement(ev);
                vt.computeCurrentVelocity(700);
                // 獲取Y方向的速度
                float mYV = vt.getYVelocity();
                if (mMoveLen == 0 || mMoveLen == -mViewHeight)
                    break;
                if (Math.abs(mYV) < 500) {
                    // 速度小於一定值的時候當作靜止釋放,這時候兩個View往哪移動取決於滑動的距離
                    if (mMoveLen <= -mViewHeight / 2) {
                        state = AUTO_UP;
                    } else if (mMoveLen > -mViewHeight / 2) {
                        state = AUTO_DOWN;
                    }
                } else {
                    // 擡起手指時速度方向決定兩個View往哪移動
                    if (mYV < 0)
                        state = AUTO_UP;
                    else
                        state = AUTO_DOWN;
                }
                mTimer.schedule(2);
                try {
                    vt.recycle();
                    vt = null;//防止第二次報錯
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;

        }
        super.dispatchTouchEvent(ev);
        return true;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        topView.layout(0, (int) mMoveLen, mViewWidth,
                topView.getMeasuredHeight() + (int) mMoveLen);
        bottomView.layout(0, topView.getMeasuredHeight() + (int) mMoveLen,
                mViewWidth, topView.getMeasuredHeight() + (int) mMoveLen
                        + bottomView.getMeasuredHeight());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (!isMeasured) {
            isMeasured = true;

            mViewHeight = getMeasuredHeight();
            mViewWidth = getMeasuredWidth();

            topView = getChildAt(0);
            bottomView = getChildAt(1);

            bottomView.setOnTouchListener(bottomViewTouchListener);
            topView.setOnTouchListener(topViewTouchListener);
        }
    }

    private OnTouchListener topViewTouchListener = new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            ScrollView sv = (ScrollView) v;
            if (sv.getScrollY() == (sv.getChildAt(0).getMeasuredHeight() - sv
                    .getMeasuredHeight()) && mCurrentViewIndex == 0)
                canPullUp = true;
            else
                canPullUp = false;
            return false;
        }
    };
    private OnTouchListener bottomViewTouchListener = new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            ScrollView sv = (ScrollView) v;
            if (sv.getScrollY() == 0 && mCurrentViewIndex == 1)
                canPullDown = true;
            else
                canPullDown = false;
            return false;
        }
    };

    class MyTimer {
        private Handler handler;
        private Timer timer;
        private MyTask mTask;

        public MyTimer(Handler handler) {
            this.handler = handler;
            timer = new Timer();
        }

        public void schedule(long period) {
            if (mTask != null) {
                mTask.cancel();
                mTask = null;
            }
            mTask = new MyTask(handler);
            timer.schedule(mTask, 0, period);
        }

        public void cancel() {
            if (mTask != null) {
                mTask.cancel();
                mTask = null;
            }
        }

        class MyTask extends TimerTask {
            private Handler handler;

            public MyTask(Handler handler) {
                this.handler = handler;
            }

            @Override
            public void run() {
                handler.obtainMessage().sendToTarget();
            }

        }
    }

}

搞定!