Android 仿京东、天猫 app 的商品详情页的布局架构, 以及功能实现

6,258 阅读4分钟

前言:电商内app,重点在于详情页商品展示,用户不仅要看到图,可以看到各种描述,以及相关规格参数。今天是coexist独家授权本公众号独家发布的《仿京东、天猫app的商品详情页功能实现》,并且已经用于他的上线项目中,coexist的简书:http://www.jianshu.com/u/ab76a93a9384,点击【阅读原文】,可看本文对应链接,下面是正文部分。


首先先看看效果实现:




最外层的布局文件

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical">
       <!-- 顶部标题 -->
      <LinearLayout
        android:id="@+id/ll_title_root"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ec0f38"
        android:orientation="vertical">
        <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="44dp"
          android:orientation="horizontal">
          <LinearLayout
            android:id="@+id/ll_back"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:paddingLeft="15dp">
            <ImageView
              android:id="@+id/iv_back"
              android:layout_width="22dp"
              android:layout_height="22dp"
              android:layout_gravity="center_vertical"
              android:src="@mipmap/address_come_back" />
          </LinearLayout>
          <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center">
            <!-- 商品、详情、评价切换的控件 -->
            <com.gxz.PagerSlidingTabStrip
              android:id="@+id/psts_tabs"
              android:layout_width="wrap_content"
              android:layout_height="32dp"
              android:layout_gravity="center"
              android:textColor="#ffffff"
              android:textSize="15sp"
              app:pstsDividerColor="@android:color/transparent"
              app:pstsDividerPaddingTopBottom="0dp"
              app:pstsIndicatorColor="#ffffff"
              app:pstsIndicatorHeight="2dp"
              app:pstsScaleZoomMax="0.0"
              app:pstsShouldExpand="false"
              app:pstsSmoothScrollWhenClickTab="false"
              app:pstsTabPaddingLeftRight="12dp"
              app:pstsTextAllCaps="false"
              app:pstsTextSelectedColor="#ffffff"
              app:pstsUnderlineHeight="0dp" />
            <TextView
              android:id="@+id/tv_title"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="图文详情"
              android:textColor="#ffffff"
              android:textSize="15sp"
              android:visibility="gone" />
          </LinearLayout>
        </LinearLayout>
      </LinearLayout>
       <!-- 功能下面有介绍 -->
      <com.hq.hsmwan.widget.NoScrollViewPager
        android:id="@+id/vp_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
     </LinearLayout>

ItemWebView是SlideDetailsLayout 的子View (SlideDetailsLayout代码太多, 放到了最后)

  • 功能为显示商品简介的webview

  • 防止往上滑动时会直接滑动到第一个View

  • 实现滑动到WebView顶部时, 让父控件重新获得触摸事件

/**
     * 商品详情页底部的webview
     */
     public class ItemWebView extends WebView {
      public float oldY;
      private int t;
      private float oldX;
      public ItemWebView(Context context) {
        super(context);
      }
      public ItemWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
      }
      public ItemWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
      }
      @Override
      public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
          case MotionEvent.ACTION_MOVE:
            float Y = ev.getY();
            float Ys = Y - oldY;
            float X = ev.getX();
            //滑动到顶部让父控件重新获得触摸事件
            if (Ys > 0 && t == 0) {
              getParent().getParent().requestDisallowInterceptTouchEvent(false);
            }
            break;
          case MotionEvent.ACTION_DOWN:
            getParent().getParent().requestDisallowInterceptTouchEvent(true);
            oldY = ev.getY();
            oldX = ev.getX();
            break;
          case MotionEvent.ACTION_UP:
            getParent().getParent().requestDisallowInterceptTouchEvent(true);
            break;
          default:
            break;
        }
        return super.onTouchEvent(ev);
      }
      @Override
      protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        this.t = t;
        super.onScrollChanged(l, t, oldl, oldt);
      }
     }
    ItemListView 也是SlideDetailsLayout的子View
    和ItemWebView功能大致一样
    /**
     * 商品详情页底部的ListView
     */
     public class ItemListView extends ListView implements AbsListView.OnScrollListener {
      private float oldX, oldY;
      private int currentPosition;
      public ItemListView(Context context) {
        super(context);
        setOnScrollListener(this);
      }
      public ItemListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOnScrollListener(this);
      }
      public ItemListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOnScrollListener(this);
      }
      @Override
      public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
          case MotionEvent.ACTION_MOVE:
            float Y = ev.getY();
            float Ys = Y - oldY;
            float X = ev.getX();
            int [] location = new int [2];
            getLocationInWindow(location);
            //滑动到顶部让父控件重新获得触摸事件
            if (Ys > 0 && currentPosition == 0) {
              getParent().getParent().requestDisallowInterceptTouchEvent(false);
            }
            break;
          case MotionEvent.ACTION_DOWN:
            getParent().getParent().requestDisallowInterceptTouchEvent(true);
            oldY = ev.getY();
            oldX = ev.getX();
            break;
          case MotionEvent.ACTION_UP:
            getParent().getParent().requestDisallowInterceptTouchEvent(true);
            break;
          default:
            break;
        }
        return super.onTouchEvent(ev);
      }
      @Override
      public void onScrollStateChanged(AbsListView view, int scrollState) {
        currentPosition = getFirstVisiblePosition();
      }
      @Override
      public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      }
     }

NoScrollViewPager为最外层的父布局

  • 当滑动到图文详情模块时, 能禁止掉ViewPager的滑动事件

/**
     * 提供禁止滑动功能的自定义ViewPager
     */
     public class NoScrollViewPager extends ViewPager {
      private boolean noScroll = false;
      public NoScrollViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
      }
      public NoScrollViewPager(Context context) {
        super(context);
      }
      public void setNoScroll(boolean noScroll) {
        this.noScroll = noScroll;
      }
      @Override
      public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
      }
      @Override
      public boolean onTouchEvent(MotionEvent arg0) {
        if (noScroll)
          return false;
        else
          return super.onTouchEvent(arg0);
      }
      @Override
      public boolean onInterceptTouchEvent(MotionEvent arg0) {
        if (noScroll)
          return false;
        else
          return super.onInterceptTouchEvent(arg0);
      }
      @Override
      public void setCurrentItem(int item, boolean smoothScroll) {
        super.setCurrentItem(item, smoothScroll);
      }
      @Override
      public void setCurrentItem(int item) {
        super.setCurrentItem(item);
      }
     }

商品模块最外层的布局是一个自定义的ViewGroup名为SlideDetailsLayout

SlideDetailsLayout内容有两个View, mFrontView(第一个View)和mBehindView(第二个View)
有两种状态, 状态设置为close就显示第一个商品数据View, open状态就显示第二个图文详情View。


这个商品详情页的架构也是本人在已上线的项目中使用,本案例对应github为:https://github.com/hexianqiao3755/GoodsInfoPage。

ps: 昨天公布福利名单中,没有向后台发送账号的兄弟姐妹们,24小时内发送下,我好汇总。发了的,我已经收到了。


第一时间获得博客更新提醒,以及更多android、小程序干货,源码分析,最新开源项目推荐 ,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。