本文共 5690 字,大约阅读时间需要 18 分钟。
要实现类似京东、天猫详情页面的滑动切换效果,我们需要以下功能:
从技术实现来看,我们需要:
项目结构大致如下:
com.xzh.gooddetail.view├── FragmentDetail.java ├── FragmentParameter.java ├── FragmentEvaluate.java └── SlideDetailsLayout.java
本节主要讲解自行实现的具有阻尼效果的滑动Layout,以及相关的Fragment逻辑。
@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) { ensureTarget(); if (null == mTarget) { return false; } if (!isEnabled()) { return false; } final int action = MotionEventCompat.getActionMasked(ev); boolean shouldIntercept = false; switch (action) { 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; } else { final float xDiffabs = Math.abs(xDiff); final float yDiffabs = Math.abs(yDiff); if (yDiffabs > mTouchSlop && yDiffabs >= xDiffabs && !(mStatus == Status.CLOSE && yDiff > 0 || mStatus == Status.OPEN && yDiff < 0)) { shouldIntercept = true; } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: shouldIntercept = false; break; } return shouldIntercept;} @Overridepublic 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 (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;} private void processTouchEvent(final float offset) { if (Math.abs(offset) < mTouchSlop) { return; } final float oldOffset = mSlideOffset; if (mStatus == Status.CLOSE) { if (offset >= 0) { mSlideOffset = 0; } else { mSlideOffset = offset; } if (mSlideOffset == oldOffset) { return; } } else if (mStatus == Status.OPEN) { final float pHeight = -getMeasuredHeight(); if (offset <= 0) { mSlideOffset = pHeight; } else { final float newOffset = pHeight + offset; mSlideOffset = newOffset; } if (mSlideOffset == oldOffset) { return; } } requestLayout();} 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();} public class FragmentDetail extends Fragment { public static FragmentDetail newInstance() { return new FragmentDetail(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_detail, container, false); }} public class FragmentParameter extends Fragment { public static FragmentParameter newInstance() { return new FragmentParameter(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_parameter, container, false); }} public class FragmentEvaluate extends Fragment { public static FragmentEvaluate newInstance() { return new FragmentEvaluate(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_evaluate, container, false); }} 以上是实现京东、天猫详情页面效果的优化版代码讲解。通过自定义的SlideDetailsLayout和多个Fragment,我们实现了复杂的滑动切换效果。代码中还包含了一些优化方案,建议在实际使用中根据项目需求进行调整和优化。
转载地址:http://mihfk.baihongyu.com/