温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么在Android中通过自定义ViewGroup实现淘宝商品详情页

发布时间:2021-05-24 18:12:52 来源:亿速云 阅读:239 作者:Leah 栏目:移动开发

这篇文章给大家介绍怎么在Android中通过自定义ViewGroup实现淘宝商品详情页,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

package com.mcoy.snapscrollview;   import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.Scroller;   public class McoySnapPageLayout extends ViewGroup {     。。。。      public interface McoySnapPage {  /**  * 返回page根节点  *   * @return  */  View getRootView();    /**  * 是否滑动到最顶端  * 第二页必须自己实现此方法,来判断是否已经滑动到第二页的顶部  * 并决定是否要继续滑动到第一页  */  boolean isAtTop();    /**  * 是否滑动到最底部  * 第一页必须自己实现此方法,来判断是否已经滑动到第二页的底部  * 并决定是否要继续滑动到第二页  */  boolean isAtBottom();  }    public interface PageSnapedListener {    /**  * @mcoy  * 当从某一页滑动到另一页完成时的回调函数  */  void onSnapedCompleted(int derection);  }     。。。。。。    /**  * 设置上下页面  * @param pageTop  * @param pageBottom  */  public void setSnapPages(McoySnapPage pageTop, McoySnapPage pageBottom) {  mPageTop = pageTop;  mPageBottom = pageBottom;  addPagesAndRefresh();  }    private void addPagesAndRefresh() {  // 设置页面id  mPageTop.getRootView().setId(0);  mPageBottom.getRootView().setId(1);  addView(mPageTop.getRootView());  addView(mPageBottom.getRootView());  postInvalidate();  }    /**  * @mcoy add  * computeScroll方法会调用postInvalidate()方法, 而postInvalidate()方法中系统  * 又会调用computeScroll方法, 因此会一直在循环互相调用, 循环的终结点是在computeScrollOffset()  * 当computeScrollOffset这个方法返回false时,说明已经结束滚动。  *   * 重要:真正的实现此view的滚动是调用scrollTo(mScroller.getCurrX(), mScroller.getCurrY());  */  @Override  public void computeScroll() {  //先判断mScroller滚动是否完成  if (mScroller.computeScrollOffset()) {  if (mScroller.getCurrY() == (mScroller.getFinalY())) {  if (mNextDataIndex > mDataIndex) {   mFlipDrection = FLIP_DIRECTION_DOWN;   makePageToNext(mNextDataIndex);  } else if (mNextDataIndex < mDataIndex) {   mFlipDrection = FLIP_DIRECTION_UP;   makePageToPrev(mNextDataIndex);  }else{   mFlipDrection = FLIP_DIRECTION_CUR;  }  if(mPageSnapedListener != null){   mPageSnapedListener.onSnapedCompleted(mFlipDrection);  }  }  //这里调用View的scrollTo()完成实际的滚动  scrollTo(mScroller.getCurrX(), mScroller.getCurrY());  //必须调用该方法,否则不一定能看到滚动效果  postInvalidate();  }  }    private void makePageToNext(int dataIndex) {  mDataIndex = dataIndex;   mCurrentScreen = getCurrentScreen();  }    private void makePageToPrev(int dataIndex) {  mDataIndex = dataIndex;   mCurrentScreen = getCurrentScreen();  }    public int getCurrentScreen() {  for (int i = 0; i < getChildCount(); i++) {  if (getChildAt(i).getId() == mDataIndex) {  return i;  }  }  return mCurrentScreen;  }    public View getCurrentView() {  for (int i = 0; i < getChildCount(); i++) {  if (getChildAt(i).getId() == mDataIndex) {  return getChildAt(i);  }  }  return null;  }    /*  * (non-Javadoc)  *   * @see  * android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)  * 重写了父类的onInterceptTouchEvent(),主要功能是在onTouchEvent()方法之前处理  * touch事件。包括:down、up、move事件。  * 当onInterceptTouchEvent()返回true时进入onTouchEvent()。  */  @Override  public boolean onInterceptTouchEvent(MotionEvent ev) {  final int action = ev.getAction();  if ((action == MotionEvent.ACTION_MOVE)  && (mTouchState != TOUCH_STATE_REST)) {  return true;  }  final float x = ev.getX();  final float y = ev.getY();    switch (action) {  case MotionEvent.ACTION_MOVE:  // 记录y与mLastMotionY差值的绝对值。    // yDiff大于gapBetweenTopAndBottom时就认为界面拖动了足够大的距离,屏幕就可以移动了。  final int yDiff = (int)(y - mLastMotionY);  boolean yMoved = Math.abs(yDiff) > gapBetweenTopAndBottom;  if (yMoved) {  if(MCOY_DEBUG) {   Log.e(TAG, "yDiff is " + yDiff);   Log.e(TAG, "mPageTop.isFlipToBottom() is " + mPageTop.isAtBottom());   Log.e(TAG, "mCurrentScreen is " + mCurrentScreen);   Log.e(TAG, "mPageBottom.isFlipToTop() is " + mPageBottom.isAtTop());  }  if(yDiff < 0 && mPageTop.isAtBottom() && mCurrentScreen == 0    || yDiff > 0 && mPageBottom.isAtTop() && mCurrentScreen == 1){   Log.e("mcoy", "121212121212121212121212");   mTouchState = TOUCH_STATE_SCROLLING;  }  }  break;  case MotionEvent.ACTION_DOWN:  // Remember location of down touch  mLastMotionY = y;  Log.e("mcoy", "mScroller.isFinished() is " + mScroller.isFinished());  mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST   : TOUCH_STATE_SCROLLING;  break;  case MotionEvent.ACTION_CANCEL:  case MotionEvent.ACTION_UP:  // Release the drag  mTouchState = TOUCH_STATE_REST;  break;  }  boolean intercept = mTouchState != TOUCH_STATE_REST;  Log.e("mcoy", "McoySnapPageLayout---onInterceptTouchEvent return " + intercept);  return intercept;  }    /*  * (non-Javadoc)  *   * @see android.view.View#onTouchEvent(android.view.MotionEvent)  * 主要功能是处理onInterceptTouchEvent()返回值为true时传递过来的touch事件  */  @Override  public boolean onTouchEvent(MotionEvent ev) {  Log.e("mcoy", "onTouchEvent--" + System.currentTimeMillis());   if (mVelocityTracker == null) {    mVelocityTracker = VelocityTracker.obtain();   }   mVelocityTracker.addMovement(ev);     final int action = ev.getAction();  final float x = ev.getX();  final float y = ev.getY();  switch (action) {  case MotionEvent.ACTION_DOWN:  if (!mScroller.isFinished()) {  mScroller.abortAnimation();  }  break;  case MotionEvent.ACTION_MOVE:   if(mTouchState != TOUCH_STATE_SCROLLING){      // 记录y与mLastMotionY差值的绝对值。      // yDiff大于gapBetweenTopAndBottom时就认为界面拖动了足够大的距离,屏幕就可以移动了。     final int yDiff = (int) Math.abs(y - mLastMotionY);     boolean yMoved = yDiff > gapBetweenTopAndBottom;     if (yMoved) {      mTouchState = TOUCH_STATE_SCROLLING;     }    }    // 手指拖动屏幕的处理    if ((mTouchState == TOUCH_STATE_SCROLLING)) {     // Scroll to follow the motion event     final int deltaY = (int) (mLastMotionY - y);     mLastMotionY = y;     final int scrollY = getScrollY();     if(mCurrentScreen == 0){//显示第一页,只能上拉时使用      if(mPageTop != null && mPageTop.isAtBottom()){      scrollBy(0, Math.max(-1 * scrollY, deltaY));      }     }else{      if(mPageBottom != null && mPageBottom.isAtTop()){      scrollBy(0, deltaY);      }     }    }  break;  case MotionEvent.ACTION_CANCEL:  case MotionEvent.ACTION_UP:  // 弹起手指后,切换屏幕的处理  if (mTouchState == TOUCH_STATE_SCROLLING) {   final VelocityTracker velocityTracker = mVelocityTracker;     velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);     int velocityY = (int) velocityTracker.getYVelocity();     if (Math.abs(velocityY) > SNAP_VELOCITY) {      if( velocityY > 0 && mCurrentScreen == 1 && mPageBottom.isAtTop()){       snapToScreen(mDataIndex-1);      }else if(velocityY < 0 && mCurrentScreen == 0){       snapToScreen(mDataIndex+1);      }else{       snapToScreen(mDataIndex);      }     } else {      snapToDestination();     }     if (mVelocityTracker != null) {      mVelocityTracker.recycle();      mVelocityTracker = null;     }  }else{  }  mTouchState = TOUCH_STATE_REST;  break;    default:  break;  }  return true;  }    private void clearOnTouchEvents(){  mTouchState = TOUCH_STATE_REST;  if (mVelocityTracker != null) {     mVelocityTracker.recycle();     mVelocityTracker = null;    }  }    private void snapToDestination() {  // 计算应该去哪个屏  final int flipHeight = getHeight() / 8;      int whichScreen = -1;   final int topEdge = getCurrentView().getTop();     if(topEdge < getScrollY() && (getScrollY()-topEdge) >= flipHeight && mCurrentScreen == 0){    //向下滑动     whichScreen = mDataIndex + 1;   }else if(topEdge > getScrollY() && (topEdge - getScrollY()) >= flipHeight && mCurrentScreen == 1){    //向上滑动    whichScreen = mDataIndex - 1;   }else{    whichScreen = mDataIndex;   }   Log.e(TAG, "snapToDestination mDataIndex = " + mDataIndex);   Log.e(TAG, "snapToDestination whichScreen = " + whichScreen);   snapToScreen(whichScreen);  }    private void snapToScreen(int dataIndex) {   if (!mScroller.isFinished())    return;      final int direction = dataIndex - mDataIndex;   mNextDataIndex = dataIndex;   boolean changingScreens = dataIndex != mDataIndex;   View focusedChild = getFocusedChild();   if (focusedChild != null && changingScreens) {    focusedChild.clearFocus();   }   //在这里判断是否已到目标位置~   int newY = 0;  switch (direction) {  case 1: //需要滑动到第二页  Log.e(TAG, "the direction is 1");  newY = getCurrentView().getBottom(); // 最终停留的位置  break;  case -1: //需要滑动到第一页  Log.e(TAG, "the direction is -1");  Log.e(TAG, "getCurrentView().getTop() is "   + getCurrentView().getTop() + " getHeight() is "   + getHeight());  newY = getCurrentView().getTop() - getHeight(); // 最终停留的位置  break;  case 0: //滑动距离不够, 因此不造成换页,回到滑动之前的位置  Log.e(TAG, "the direction is 0");  newY = getCurrentView().getTop(); //第一页的top是0, 第二页的top应该是第一页的高度  break;  default:  break;  }   final int cy = getScrollY(); // 启动的位置   Log.e(TAG, "the newY is " + newY + " cy is " + cy);   final int delta = newY - cy; // 滑动的距离,正值是往左滑<—,负值是往右滑—>   mScroller.startScroll(0, cy, 0, delta, Math.abs(delta));   invalidate();  }     }

McoySnapPage是定义在VIewGroup的一个接口, 比如说我们需要类似某东商品详情那样,有上下两页的效果。 那我就需要自己定义两个类实现这个接口,并实现接口的方法。getRootView需要返回当前页需要显示的布局内容;isAtTop需要返回当前页是否已经在顶端; isAtBottom需要返回当前页是否已经在底部

onInterceptTouchEventonTouchEvent决定当前的滑动状态, 并决定是有当前VIewGroup拦截touch事件还是由子view去消费touch事件

Android是什么

Android是一种基于Linux内核的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由美国Google公司和开放手机联盟领导及开发。

关于怎么在Android中通过自定义ViewGroup实现淘宝商品详情页就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI