Android 自定义控件 轻松实现360软件详情页(3)

看完了构造以后,由于我们使用的是LinearLayout,直接setOrientation(LinearLayout.VERTICAL);也就不必去layout了,控件都自定垂直排列了。那么我们在onMeasure中还需要做些处理。

2、onMeasure

@Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
 {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  ViewGroup.LayoutParams params = mViewPager.getLayoutParams();
  params.height = getMeasuredHeight() - mNav.getMeasuredHeight();
 }

@Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh)
 {
  super.onSizeChanged(w, h, oldw, oldh);
  mTopViewHeight = mTop.getMeasuredHeight();
 }

主要是去设置ViewPager的高度,给它一个固定值,ViewPager自己在测量自己的时候,你要是不给它固定值,可能测量结果与你的预期会差距很大。比如你给它设置个WRAP_CONTENT,你希望他去计算孩子的高度去设置自己的,那么你就想多了。大家可以看下ViewPager测量的源码:

可以看到,对于AT_MOST和EXACTLY两种模式,都是直接读取父类的传入的测量值,也就是说,他不会去测量自己孩子的高度。然后如果模式是:UNSPECIFIED,那么高度直接为0呢。这里大家如果做过这个例子,应该能遇到这种情况,ScrollView中放ViewPager时,测量模式就是UNSPECIFIED,那么Vp直接不显示,原因就在这里。

扯远了,回来,我们继续。

我们设置为Vp的值以后,理论上来说,我们的显示已经正常了,控件都按照我们的预期显示了,但是,但是什么呢?我们现在在自定义的LinearLayout,那么移动是不是应该我们自己去写。

移动的代码很简单,想必大家都知道,直接拿到dx,然后scrollBy就行了。

3、onTouchEvent

@Override
 public boolean onTouchEvent(MotionEvent event)
 {
  mVelocityTracker.addMovement(event);
  int action = event.getAction();
  float y = event.getY();

switch (action)
  {
  case MotionEvent.ACTION_DOWN:
   if (!mScroller.isFinished())
    mScroller.abortAnimation();
   mVelocityTracker.clear();
   mVelocityTracker.addMovement(event);
   mLastY = y;
   return true;
  case MotionEvent.ACTION_MOVE:
   float dy = y - mLastY;

if (!mDragging && Math.abs(dy) > mTouchSlop)
   {
    mDragging = true;
   }
   if (mDragging)
   {
    scrollBy(0, (int) -dy);
    mLastY = y;
   }
   break;
  case MotionEvent.ACTION_CANCEL:
   mDragging = false;
   if (!mScroller.isFinished())
   {
    mScroller.abortAnimation();
   }
   break;
  case MotionEvent.ACTION_UP:
   mDragging = false;
   mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
   int velocityY = (int) mVelocityTracker.getYVelocity();
   if (Math.abs(velocityY) > mMinimumVelocity)
   {
    fling(-velocityY);
   }
   mVelocityTracker.clear();
   break;
  }

return super.onTouchEvent(event);
 }

比较简单哈,我们因为只需要判断y方向的,所以down的时候记录下y的值,然后move的时候拿到dy,直接去进去scrollBy就好,当然我们在整个过程中.addMovement(event);所以,up的时候,我们得到v方向的velocityY,调用fling进行移动。 

还好fling的核心代码OverScroller给我们实现了,so nice。

大家应该清楚,我们使用Scroller这样的辅助类时,它们帮我们完成的,知识数学方面的计算,至于自动我们还是需要自己去干的。

那怎么干,在哪干?这个无非就是重写computeScroll方法,在里面判断scroller是否结束,如果没有,则scrollTo一下,最后记得invalidate,相关代码:

public void fling(int velocityY)
 {
  mScroller.fling(0, getScrollY(), 0, velocityY, 0, 0, 0, mTopViewHeight);
  invalidate();
 }

@Override
 public void scrollTo(int x, int y)
 {
  if (y < 0)
  {
   y = 0;
  }
  if (y > mTopViewHeight)
  {
   y = mTopViewHeight;
  }
  if (y != getScrollY())
  {
   super.scrollTo(x, y);
  }

isTopHidden = getScrollY() == mTopViewHeight;

}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/3ad01d53e22f3c56cd5518aaee927350.html