1.参考借鉴

  • Android仿京东商品详情页上拉查看图文详情
  • [模仿淘宝、京东、蘑菇街商品详情页,可嵌套ListView、WebView、ViewPager、FragmentTabhost等](https://github.com/happylishang/DragScrollDetailsLayout#3%E6%94%AF%E6%8C%81%E6%94%AF%E6%8C%81scrollviewlistview
    )

效果图

简单介绍

  • 1,自定义控件
public class DragScrollDetailsLayout extends LinearLayout {public interface OnSlideFinishListener {void onStatueChanged(CurrentTargetIndex status);}public enum CurrentTargetIndex {UPSTAIRS,DOWNSTAIRS;public static CurrentTargetIndex valueOf(int index) {return 1 == index ? DOWNSTAIRS : UPSTAIRS;}}private static final float DEFAULT_PERCENT = 0.3f;private static final int DEFAULT_DURATION = 300;private int mMaxFlingVelocity;private int mMiniFlingVelocity;private int mDefaultPanel = 0;private int mDuration = DEFAULT_DURATION;private float mTouchSlop;private float mDownMotionY;private float mDownMotionX;private float mInitialInterceptY;public void setPercent(float percent) {mPercent = percent;}private float mPercent = DEFAULT_PERCENT;/*** flag for listview or scrollview ,if child overscrolled ,do not judge view region 滚过头了,还是可以滚动*/private boolean mChildHasScrolled;private View mUpstairsView;private View mDownstairsView;private View mCurrentTargetView;private Scroller mScroller;private VelocityTracker mVelocityTracker;private OnSlideFinishListener mOnSlideDetailsListener;private CurrentTargetIndex mCurrentViewIndex = CurrentTargetIndex.UPSTAIRS;public DragScrollDetailsLayout(Context context) {this(context, null);}public DragScrollDetailsLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public DragScrollDetailsLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DragScrollDetailsLayout, defStyleAttr, 0);mPercent = a.getFloat(R.styleable.DragScrollDetailsLayout_percent, DEFAULT_PERCENT);mDuration = a.getInt(R.styleable.DragScrollDetailsLayout_duration, DEFAULT_DURATION);mDefaultPanel = a.getInt(R.styleable.DragScrollDetailsLayout_default_panel, 0);a.recycle();mScroller = new Scroller(getContext(), new DecelerateInterpolator());mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();mMaxFlingVelocity = ViewConfiguration.get(getContext()).getScaledMaximumFlingVelocity();mMiniFlingVelocity = ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();setOrientation(VERTICAL);}public void setOnSlideDetailsListener(OnSlideFinishListener listener) {this.mOnSlideDetailsListener = listener;}@Overrideprotected void onFinishInflate() {super.onFinishInflate();final int childCount = getChildCount();if (1 >= childCount) {throw new RuntimeException("SlideDetailsLayout only accept childs more than 1!!");}mUpstairsView = getChildAt(0);mDownstairsView = getChildAt(1);}/*** requestDisallowInterceptTouchEvent guarantee DragScrollDetailsLayout intercept event as wish*/@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {if (!mScroller.isFinished()) {resetDownPosition(ev);return true;}Log.v("lishang", "" + getScrollY());requestDisallowInterceptTouchEvent(false);return super.dispatchTouchEvent(ev);}/*** intercept rules:* 1. The vertical displacement is larger than the horizontal displacement;* 2. Panel stauts is UPSTAIRS:  slide up* 3. Panel status is DOWNSTAIRS:slide down* 4. child can requestDisallowInterceptTouchEvent();*/@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {switch (ev.getActionMasked()) {case MotionEvent.ACTION_DOWN:resetDownPosition(ev);break;case MotionEvent.ACTION_MOVE:adjustValidDownPoint(ev);return checkCanInterceptTouchEvent(ev);default:break;}return false;}private void resetDownPosition(MotionEvent ev) {mDownMotionX = ev.getX();mDownMotionY = ev.getY();if (mVelocityTracker == null) {mVelocityTracker = VelocityTracker.obtain();}mVelocityTracker.clear();mChildHasScrolled = false;mInitialInterceptY = (int) ev.getY();}@Overridepublic boolean onTouchEvent(MotionEvent ev) {switch (ev.getActionMasked()) {case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:flingToFinishScroll();recycleVelocityTracker();break;case MotionEvent.ACTION_MOVE:scroll(ev);break;default:break;}return true;}private boolean checkCanInterceptTouchEvent(MotionEvent ev) {final float xDiff = ev.getX() - mDownMotionX;final float yDiff = ev.getY() - mDownMotionY;if (!canChildScrollVertically((int) yDiff, ev)) {mInitialInterceptY = (int) ev.getY();if (Math.abs(yDiff) > mTouchSlop && Math.abs(yDiff) >= Math.abs(xDiff)&& !(mCurrentViewIndex == CurrentTargetIndex.UPSTAIRS && yDiff > 0|| mCurrentViewIndex == CurrentTargetIndex.DOWNSTAIRS && yDiff < 0)) {return true;}}return false;}private void adjustValidDownPoint(MotionEvent event) {if (mCurrentViewIndex == CurrentTargetIndex.UPSTAIRS && event.getY() > mDownMotionY|| mCurrentViewIndex == CurrentTargetIndex.DOWNSTAIRS && event.getY() < mDownMotionY) {mDownMotionX = event.getX();mDownMotionY = event.getY();}}/*** 拦截之后的拖动*/private void scroll(MotionEvent event) {if (mCurrentViewIndex == CurrentTargetIndex.UPSTAIRS) {if (getScrollY() <= 0 && event.getY() >= mInitialInterceptY) {mInitialInterceptY = (int) event.getY();}int distance = mInitialInterceptY - event.getY() >= 0 ? (int) (mInitialInterceptY - event.getY()) : 0;scrollTo(0, distance);} else {if (getScrollY() >= mUpstairsView.getMeasuredHeight() && event.getY() <= mInitialInterceptY) {mInitialInterceptY = (int) event.getY();}int distance = event.getY() <= mInitialInterceptY ? mUpstairsView.getMeasuredHeight(): (int) (mInitialInterceptY - event.getY() + mUpstairsView.getMeasuredHeight());scrollTo(0, distance);}mVelocityTracker.addMovement(event);}/*** 清理VelocityTracker*/private void recycleVelocityTracker() {if (mVelocityTracker != null) {mVelocityTracker.clear();mVelocityTracker.recycle();mVelocityTracker = null;}}/*** if speed is enough even though offset is not enough go*/private void flingToFinishScroll() {final int pHeight = mUpstairsView.getMeasuredHeight();final int threshold = (int) (pHeight * mPercent);float needFlingDistance = 0;if (CurrentTargetIndex.UPSTAIRS == mCurrentViewIndex) {if (getScrollY() <= 0) {needFlingDistance = 0;} else if (getScrollY() <= threshold) {if (needFlingToToggleView()) {needFlingDistance = pHeight - getScrollY();mCurrentViewIndex = CurrentTargetIndex.DOWNSTAIRS;} else {needFlingDistance = -getScrollY();}} else {needFlingDistance = pHeight - getScrollY();mCurrentViewIndex = CurrentTargetIndex.DOWNSTAIRS;}} else if (CurrentTargetIndex.DOWNSTAIRS == mCurrentViewIndex) {if (pHeight <= getScrollY()) {needFlingDistance = 0;} else if (pHeight - getScrollY() < threshold) {if (needFlingToToggleView()) {needFlingDistance = -getScrollY();mCurrentViewIndex = CurrentTargetIndex.UPSTAIRS;} else {needFlingDistance = pHeight - getScrollY();}} else {needFlingDistance = -getScrollY();mCurrentViewIndex = CurrentTargetIndex.UPSTAIRS;}}mScroller.startScroll(0, getScrollY(), 0, (int) needFlingDistance, mDuration);if (mOnSlideDetailsListener != null) {mOnSlideDetailsListener.onStatueChanged(mCurrentViewIndex);}postInvalidate();}private boolean needFlingToToggleView() {mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity);if (mCurrentViewIndex == CurrentTargetIndex.UPSTAIRS) {if (-mVelocityTracker.getYVelocity() > mMiniFlingVelocity) {return true;}} else {if (mVelocityTracker.getYVelocity() > mMiniFlingVelocity) {return true;}}return false;}private View getCurrentTargetView() {return mCurrentViewIndex == CurrentTargetIndex.UPSTAIRS? mUpstairsView : mDownstairsView;}@Overridepublic void computeScroll() {super.computeScroll();if (mScroller.computeScrollOffset()) {scrollTo(0, mScroller.getCurrY());postInvalidate();}}/**** 复用已经实现的View,省却了测量布局之类的麻烦*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);measureChildren(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());}protected boolean canChildScrollVertically(int offSet, MotionEvent ev) {mCurrentTargetView = getCurrentTargetView();return canScrollVertically(mCurrentTargetView, -offSet, ev);}/**** judge is event  is in current view* 判断MotionEvent是否处于View上面*/protected boolean isTransformedTouchPointInView(MotionEvent ev, View view) {float x = ev.getRawX();float y = ev.getRawY();int[] rect = new int[2];view.getLocationInWindow(rect);float localX = x - rect[0];float localY = y - rect[1];return localX >= 0 && localX < (view.getRight() - view.getLeft())&& localY >= 0 && localY < (view.getBottom() - view.getTop());}/**** first    can view self  ScrollVertically* seconde  if View is ViewPager only judge current page* third    if view is viewgroup check it`s children*/private boolean canScrollVertically(View view, int offSet, MotionEvent ev) {if (!mChildHasScrolled && !isTransformedTouchPointInView(ev, view)) {return false;}if (ViewCompat.canScrollVertically(view, offSet)) {mChildHasScrolled = true;return true;}if (view instanceof ViewPager) {return canViewPagerScrollVertically((ViewPager) view, offSet, ev);}if (view instanceof ViewGroup) {ViewGroup vGroup = (ViewGroup) view;for (int i = 0; i < vGroup.getChildCount(); i++) {if (canScrollVertically(vGroup.getChildAt(i), offSet, ev)) {mChildHasScrolled = true;return true;}}}return false;}private boolean canViewPagerScrollVertically(ViewPager viewPager, int offset, MotionEvent ev) {if(viewPager.getAdapter() instanceof DragDetailFragmentPagerAdapter){View showView = ((DragDetailFragmentPagerAdapter) viewPager.getAdapter()).getPrimaryItem();return showView != null && canScrollVertically(showView, offset, ev);}else {return false;}}@Overrideprotected void onScrollChanged(int l, int t, int oldl, int oldt) {super.onScrollChanged(l, t, oldl, oldt);}public void scrollToTop() {if (mCurrentViewIndex == CurrentTargetIndex.DOWNSTAIRS) {mScroller.startScroll(0, getScrollY(), 0, -getScrollY(), mDuration);mCurrentViewIndex= CurrentTargetIndex.UPSTAIRS;postInvalidate();}if (mOnSlideDetailsListener != null) {mOnSlideDetailsListener.onStatueChanged(mCurrentViewIndex);}}
}
  • 2,自定义属性
<declare-styleable name="DragScrollDetailsLayout"><!-- float value for indicate the moment of switch panel--><attr name="percent" format="float" /><!-- how long the animation keep--><attr name="duration" format="integer" /><!-- default panel to show after init--><attr name="default_panel" format="enum"><enum name="front" value="0" /><enum name="behind" value="1" /></attr></declare-styleable>
  • 3,DragDetailFragmentPagerAdapter用途不明(代替FragmentPagerAdapter)
public abstract class DragDetailFragmentPagerAdapter extends FragmentPagerAdapter {private View mCurrentView;public DragDetailFragmentPagerAdapter(FragmentManager fm) {super(fm);}@Overridepublic void setPrimaryItem(ViewGroup container, int position, Object object) {if (object instanceof View) {mCurrentView = (View) object;} else if (object instanceof Fragment) {Fragment fragment = (Fragment) object;mCurrentView = fragment.getView();}}public View getPrimaryItem() {return mCurrentView;}
}

其余看源码

地址

仿京东天猫商品详情页相关推荐

  1. Android仿京东、天猫商品详情页

    前言 前面在介绍控件TabLayout控件和CoordinatorLayout使用的时候说了下实现京东.天猫详情页面的效果,今天要说的是优化版,是我们线上实现的效果,首先看一下效果: 项目结构分析 首 ...

  2. 京东手机商品详情页技术解密

    转载地址:http://geek.csdn.net/news/detail/134812 京东手机单品页在每次大促时承载所有流量的入口,它被天然赋予的一个标签就是抗压,对系统的稳定性.性能方面要求极其 ...

  3. 【京东】商品详情页采集

    采集场景 打开京东商品详情页(实例网址:https://item.jd.com/100006607659.html#crumb-wrap ),采集点击不同的参数(颜色.版本等)后得到的数据(商品编号. ...

  4. 【京东】商品详情页+商品列表数据采集

    作为国内最大的电商平台之一,京东数据采集具有多个维度. 有人需要采集商品信息,包括品类.品牌.产品名.价格.销量等字段,以了解商品销售状况.热门商品属性,进行市场扩大和重要决策: 有人需要采集产品评论 ...

  5. Android 仿淘宝商品详情页下拉足迹Demo

    DropDownMultiPager 仿淘宝等商品详情页下拉足迹效果SimpleDemo 可colne之后看MainActivity的调用,方便二次开发 依赖 compile 'com.nineold ...

  6. 天猫图书采集 php,采集天猫商品详情页信息

    //天猫规则 function caiji1(){ header("Content-type: text/html; charset=utf-8"); $url=$_POST['t ...

  7. 仿淘宝商品详情页图片滑动并且数字也跟着变化

    今天遇到需求需要做个淘宝那样的商品详情页如图(这里只差放图片了)支持移动端,当然用的是swiper.js支持左右滑动 上代码 html代码 <div class="swiper-con ...

  8. Android开发之仿淘宝商品详情页

    看到有人在问如何实现淘宝商品详情页效果,手痒了就撸了一个,献上效果图 大致梳理一下思路,这里不提供源码 状态栏透明使用开源库StatusBarCompat,为了兼容手机4.4 dependencies ...

  9. 仿淘宝商品详情页TabLayout+ListView

    第一次写博客,我是一名Android的小码农写代码也有三四年了.有点好玩的跟大家分享一下 项目对商品详情页改版有新需求.顶部是一个渐变的Title包括"宝贝","详情&q ...

最新文章

  1. 悉尼大学 伦敦大学联合出品:知识蒸馏最新综述
  2. gradle构建工具_Gradle:我们需要另一个构建工具吗?
  3. 【OpenCV 例程 200篇】98. 统计排序滤波器
  4. ZZULIOJ 1126: 布尔矩阵的奇偶性
  5. 教育|施一公:研究生最重要的素质是什么?
  6. SQL中过滤条件放在on和where中的区别
  7. PostgreSQL学习总结(2)—— PostgreSQL 语法
  8. 激战 5G:国内外技术的分水岭
  9. 配置hadoop 使用fair scheduler调度器
  10. Spring mvc Interceptor 解决Session超时配置流程
  11. 编译OpenJDK12:freetypeScaler.obj error LINK2019 无法解析的外部符号
  12. Nginx与tomcat组合的简单使用
  13. css行内样式的属性设置,css的外部样式的设置
  14. java的jdk和jre有什么区别
  15. USB Repair v8.1.3.1285 – USB 修复工具
  16. 安卓 播放MP3 实现歌词同步例子
  17. 【STM32学习】(30)STM32实现18B20温度采集(标准库和HAL库实现)
  18. lower_bound( )和upper_bound( )的常见用法
  19. MySQL COUNT(*) 和 COUNT(1) 比较
  20. iOS开发 - App语言国际化

热门文章

  1. #父与子的编程之旅#第十三章
  2. 当程序员5年,他从来不加班,工资居然还每年都在涨...
  3. Cmake在Windows下安装Opencv3.2遇到的问题
  4. Python英文词频统计(哈姆雷特)程序示例
  5. Twig中控制保留小数位数
  6. tesseract::tesseractAPI::setVariable()参数列表
  7. c语言中signal函数详细说明--举例
  8. js下载文件的几种方式
  9. c51时钟数码管显示流程图_基于51单片机的8位数码管电子时钟仿真图及源代码详细资料概述...
  10. GBK 代码集字符定义表