使用端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…