仿淘宝京东的详情页上下滚动的效果-修改了原作者的bug并增加滚动进度百分比监听...

使用端activity CourseDetailActivity

package cn.zhiup.mobile.main.coursedetail

import android.support.v4.app.Fragment
import cn.zhiup.mobile.R
import com.zhiup.base.base.BaseActivity
import com.zhiup.base.widget.scrollwidget.GraphicDetailsLayout

class CourseDetailActivity: BaseActivity(){
    override fun getLayoutId(): Int = R.layout.activity_course_detail

    override fun initView() {
        val gdLayout = findViewById(R.id.gdlayout) as GraphicDetailsLayout
        gdLayout.addFragment(arrayOf(CourseDetailTopFragment(), CourseDetailBottomFragment()), supportFragmentManager)
    }

    override fun initData() {
    //此监听可以根据滚动比例来来做一些个性化设置,此处是我自己设置 改变title的alpha值 不用可以去掉
    gdlayout.setOnPercentListener{
            if(it<0.1){
                nav_layout.alpha=0f
            }else{
                nav_layout.alpha=it
            }
        }
    }

    override fun initEvent() {
    }

}
复制代码

xml activity_course_detail

"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    "@+id/gdlayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    "@color/white"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:gravity="center_vertical"
        android:layout_width="match_parent"
        android:layout_height="@dimen/x50">
        "¥3999.00"
            android:layout_marginLeft="@dimen/x20"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content" />
        "@drawable/icon_zx"
            android:layout_marginRight="@dimen/x4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        "咨询"
            android:layout_marginRight="@dimen/x26"
            android:textSize="@dimen/text_size_12"
            android:textColor="@color/color_707070"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        

CourseDetailTopFragment

package cn.zhiup.mobile.main.coursedetail;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.bumptech.glide.Glide;

import cn.zhiup.mobile.R;

/**
 * Created by chenpengfei on 2016/6/3.
 */
public class CourseDetailTopFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View contentView = inflater.inflate(R.layout.fragment_detail_top, null);
//        Glide.with(getActivity()).load(R.drawable.log_pic).into((ImageView) contentView.findViewById(R.id.logo));
        return contentView;
    }
}

复制代码

CourseDetailBottomFragment

package cn.zhiup.mobile.main.coursedetail;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.bumptech.glide.Glide;

import cn.zhiup.mobile.R;

/**
 * Created by chenpengfei on 2016/6/3.
 */
public class CourseDetailBottomFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View contentView = inflater.inflate(R.layout.fragment_detail_bottom, null);
        Glide.with(getActivity()).load(R.drawable.icon_consulting).into((ImageView) contentView.findViewById(R.id.detail));
        return contentView;
    }
}

复制代码

GraphicDetailsLayout

package com.zhiup.base.widget.scrollwidget;

import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
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.LinearLayout;

import com.blankj.utilcode.util.SizeUtils;

/**
 * Created by zcz on 2016/11/4.
 */
public class GraphicDetailsLayout extends LinearLayout {

    private boolean mIntercept;
    private GDScrollView mUpScrollView, mBottomScrollView;
    private int mUpSVMarginTop = 0;
    private int mInitMarginTop = 0;
    private float mInitY;
    private int mTouchSlop;
    private String mCurrentTag = "";
    private int halfHeight;

    public GraphicDetailsLayout(Context context) {
        super(context);
    }

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

    public GraphicDetailsLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mIntercept = false;
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    private void init(Context context) {
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        setOrientation(LinearLayout.VERTICAL);
        mUpScrollView = inflateScrollView(context, GDScrollView.TAG_ONE, GDScrollView.ID_ONE);
        mBottomScrollView = inflateScrollView(context, GDScrollView.TAG_TWO, GDScrollView.ID_TWO);
        addView(mUpScrollView);
        addView(mBottomScrollView);
    }


    private GDScrollView inflateScrollView(Context context, String tag, int id) {
        GDScrollView gdScrollView = new GDScrollView(context);
        gdScrollView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        gdScrollView.setTag(tag);
        gdScrollView.setScrollListener(new ScrollListener() {
            @Override
            public void scrollBottom(boolean intercept, String tag) {
                mIntercept = intercept;
                mCurrentTag = tag;
            }
        });
        gdScrollView.addView(inflateLl(context, id));
        return gdScrollView;
    }

    private LinearLayout inflateLl(Context context, int id) {
        LinearLayout ll = new LinearLayout(context);
        ll.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        ll.setOrientation(LinearLayout.VERTICAL);
        ll.setId(id);
        return ll;
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(mIntercept) return true;
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() * 2);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        halfHeight = getMeasuredHeight() / 2;
        mUpScrollView.layout(0, mUpSVMarginTop, getMeasuredWidth(), mUpSVMarginTop + halfHeight);
        //底部的marginTop需要在这增加 SizeUtils.dp2px(50) 否则怎么设置都不起作用
        mBottomScrollView.layout(0, mUpSVMarginTop + halfHeight+ SizeUtils.dp2px(50), getMeasuredWidth(), mUpSVMarginTop + getMeasuredHeight());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                if(mInitY == 0) {
                    mInitY = event.getY();
                } else {
                    int offset = (int)(event.getY() - mInitY);
                    if(Math.abs(offset) > mTouchSlop) {
                        int delayOffset = offset * 7 / 10;
                        if(mCurrentTag.equals(GDScrollView.TAG_ONE)) {
                            mUpSVMarginTop = mInitMarginTop + delayOffset;
                            if(mUpSVMarginTop > 0) mUpSVMarginTop = 0;
                        } else {
                            mUpSVMarginTop = - halfHeight + delayOffset;
                        }
                        requestLayout();
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                mIntercept = false;
                mInitY = 0;
                if(mCurrentTag.equals(GDScrollView.TAG_ONE)) {
                    if(Math.abs(mUpSVMarginTop) > halfHeight / 8) {
                        startAnimation(mUpSVMarginTop, halfHeight - Math.abs(mUpSVMarginTop), false);
                    } else {
                        startAnimation(mUpSVMarginTop, Math.abs(mUpSVMarginTop), true);
                    }
                } else {
                    if(Math.abs(mUpSVMarginTop) < halfHeight * 7 / 8) {
                        startAnimation(mUpSVMarginTop, Math.abs(mUpSVMarginTop), true);
                    } else {
                        startAnimation(mUpSVMarginTop, halfHeight - Math.abs(mUpSVMarginTop), false);
                    }
                }
                requestLayout();
                break;
        }
        return true;
    }

    public void addFragment(Fragment[] fragmentArray, FragmentManager fragmentManager) {
        if(fragmentArray == null || fragmentArray.length < 2 || fragmentManager == null || mBottomScrollView == null || mUpScrollView == null) return;
        mUpScrollView.addFragment(fragmentArray[0], fragmentManager);
        mBottomScrollView.addFragment(fragmentArray[1], fragmentManager);
    }

    private void startAnimation(final int start, final int moveOffset, final boolean isPlus) {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int progressOffset = (int) (moveOffset * ((float) animation.getAnimatedValue()));
                progressOffset = isPlus ? -progressOffset : progressOffset;
                mUpSVMarginTop = start - progressOffset;
                requestLayout();
            }
        });
        valueAnimator.setDuration(moveOffset<0?0:moveOffset/ mTouchSlop * 10);
        valueAnimator.start();
    }

    public interface ScrollListener {
        void scrollBottom(boolean intercept, String tag);
    }

    public void setOnPercentListener(final IPercentListener iPercentListener){
        mUpScrollView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                if (halfHeight!=0&&top!=0){
//                    Log.i("-->","top="+top+"halfHeight="+halfHeight+"  top/halfHeight="+((float)top/halfHeight));
                    iPercentListener.onPercentChanged(-(float)top/halfHeight);
                }
            }
        });
    }
}



复制代码

GDScrollView

package com.zhiup.base.widget.scrollwidget;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.ScrollView;

/**
 * Created by chenpengfei on 2016/11/4.
 */
public class GDScrollView extends ScrollView {

    private LinearLayout mLl;
    private int mLlHeight;
    public static final String TAG_ONE = "up";
    public static final String TAG_TWO = "down";
    public static final int ID_ONE = 11111;
    public static final int ID_TWO = 22222;
    private GraphicDetailsLayout.ScrollListener mScrollListener;

    public GDScrollView(Context context) {
        super(context);
    }

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

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

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

    public void setScrollListener(GraphicDetailsLayout.ScrollListener scrollListener) {
        mScrollListener = scrollListener;
    }


    public void addFragment(Fragment fragment, FragmentManager fragmentManager) {
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        if(mLl == null) mLl = (LinearLayout) getChildAt(0);
        fragmentTransaction.replace(mLl.getId(), fragment);
        fragmentTransaction.commit();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mLlHeight = mLl.getMeasuredHeight();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mLl = (LinearLayout) getChildAt(0);
    }

    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);

        if(getTag().equals(TAG_ONE)) {
            //上面的界面滚动到底部的时候
            if(isScrollBottom()) {
                criticalPointOperation(false, true, TAG_ONE);
            }
        }

        if(getTag().equals(TAG_TWO)) {
            //下面的界面滚动到顶部的时候
            if(getScrollY() <= 0) {
                criticalPointOperation(false, true, TAG_TWO);
            }
        }
    }

    private void criticalPointOperation(boolean allow, boolean intercept, String tag) {
        getParent().requestDisallowInterceptTouchEvent(allow);
        if(mScrollListener != null) mScrollListener.scrollBottom(intercept, tag);
    }

    public boolean isScrollBottom() {
        return getScrollY() >= (mLlHeight - getMeasuredHeight());
    }

}

复制代码

fragment_detail_top.xml

"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    "@+id/logo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>

    "15dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="芭欧2016新款秋冬双面呢修身长袖纯色毛呢外套中长款羊毛呢子大衣, 经典廓型设 纯手工工艺 平整的走线 精工细作"/>

    "wrap_content"
        android:layout_height="30dp"
        android:layout_gravity="center_horizontal"
        android:text="------------------------查看图文详情-------------------"/>



复制代码

fragment_detail_bottom.xml

"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    "@+id/detail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>


    "15dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="材质成分: 羊毛100%销售渠道类型: 纯电商(只在线上销售)品牌: Bool/芭欧货号: BY3050服装版型: 直筒风格: 通勤通勤: 韩版衣长: 中长款袖长: 长袖领子: 西装领袖型: 常规衣门襟: 暗扣图案: 纯色流行元素/工艺: 口袋适用年龄: 30-34周岁上市年份季节: 2015年夏季颜色分类: 藕粉 罂粟红 驼色 橄榄绿 草绿 衣玫红尺码: S M L XL"/>



复制代码

效果图

github地址

github.com/chenpengfei…

原文

www.jianshu.com/p/433b520dc…

转载于:https://juejin.im/post/5bc83d3be51d450e74291e1c

你可能感兴趣的:(仿淘宝京东的详情页上下滚动的效果-修改了原作者的bug并增加滚动进度百分比监听...)