android自定义系列

上大街网app的个人中心,感觉界面做的还是挺好的,所以仿写了一个。虽然没有加上动画,但是主要的功能还是实现了的。好了看图~~~
在这里插入图片描述
android自定义系列(七)–仿大街网个人中心页面
当向上推的时候,上面的TextView隐藏后,listview就会在顶部。当向下拉的时候,又会重新拉出上面的内容。
好了,思路分析~~~
在这里我们继承linearlayout,设置方向为垂直。看看布局文件。

xmlns:tools=“http://schemas.android.com/tools”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
android:orientation=“vertical”
tools:context=".MainActivity" >

      android:id="@+id/tv"
   android:text="你好,你猜可以滑动不?"
   android:background="#ffeeff"
   android:gravity="center"
   android:layout_width="match_parent"
   android:layout_height="300dp" />

      android:id="@+id/listview"
   android:layout_width="match_parent"
   android:layout_height="match_parent" />

这个没什么好说的了,接着就是滑动处理了。为了能够让滑动更顺畅,我们用OverScroller来做辅助,当然,onTouchEvent是必须的。
在构造函数初始化OverScroller
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroll = new OverScroller(context);
}
我们先来实现,滑动操作(万事开头难,从简单做起),滑动重写撒方法呢~~没错onTouchEvent
@Override
public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {

   case MotionEvent.ACTION_DOWN:

      firstY = (int) event.getY();

      break;
   case MotionEvent.ACTION_MOVE:

      lastY = event.getY();

      float dy = lastY - firstY;

      if (Math.abs(dy) > mTouchSlop) {

         scrollBy(0, (int) -dy);
         firstY = lastY;
      }
      break;
   case MotionEvent.ACTION_UP:

      break;
  default:

      break;
   }

   return super.onTouchEvent(event);

}
在按下和移动两个地方做文章,计算Y轴的差值,用scrollBy进行移动。好了,一个能移动的View就基本出来了,但是我们会发现,会出现listview会拦消耗我们自定义View的move事件,所以,根据事件分发机制,我们需要拦截掉move事件~~
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

   float y = ev.getY();

   switch (ev.getAction()) {

   case MotionEvent.ACTION_DOWN:

      firstY = y;
      break;
   case MotionEvent.ACTION_MOVE:

         return true;// 父组件拦截事件,
   case MotionEvent.ACTION_UP:

      break;
  default:

      break;
   }

   return super.onInterceptTouchEvent(ev);
}

拦截掉事件后,好了又出了一个BUG,当我们不断的向下拉的时候,我们的TextView上面会出现空白。产生的原因是画布的无限性决定的。没办法,我们只有人为去控制了,重写onscrollTo方法~~
@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);
   }
}

这 段代码的意思是,当视图的y坐标小于或者等于0的时候,y值为0,所以TextView就不会出现空白了,同理,当TextView向上推的时候,当Y值 超过TextView的高度的时候就设置为TextView的高度。好了,到这里,革命基本完成了一半,但是还有bug,当隐藏TextView的时候, 我们需要不要拦截listview的滑动事件~~这个简单,我们只有找到这个临界点就可以了。这里有三种情况,一种是TextView还没有隐藏,这里我 们要拦截掉、另一种是TextView已经隐藏掉,但是向上拉,由于刚隐藏所以又会被拦截,我们依据dy做依据,如果<0则向上,我们拦截,否则不 拦截。
case MotionEvent.ACTION_MOVE:

      float dy = y - firstY;
      if (Math.abs(dy) > mTouchSlop && !isHidden) {

         return true;// 父组件拦截事件,
      }else {

        if(firstVisibleItems == 0 && dy > 0)//listView滚动到顶部并且向上滑动
         {
            return true;
         }else
         {
            return false;
         }
      }

其中dy是move事件在y方向的差值。到这里,可以说是完成了70%了。为了丰富用户体验,我们用一个速度跟踪器来帮助视图滑动。
在onTouchEvent方法初始化,并将当前事件添加进去
@Override
public boolean onTouchEvent(MotionEvent event) {

   if (null == mVelocityTracker) {
     mVelocityTracker = VelocityTracker.obtain();// 获得VelocityTracker类实例
   }

  mVelocityTracker.addMovement(event);

}
然后在手指抬起的时候触获取x和y方向的速度
case MotionEvent.ACTION_UP:

      final VelocityTracker tracker = mVelocityTracker;

      // 设置maxVelocity值为0.1时,速率大于0.01时,显示的速率都是0.01,速率小于0.01时,显示正常
     tracker.computeCurrentVelocity(1, (float) 0.01);

      // 设置units的值为1000,意思为一秒时间内运动了多少个像素
     tracker.computeCurrentVelocity(1000);

      int velocityY = (int) mVelocityTracker.getYVelocity();
      int velocityX = (int) mVelocityTracker.getXVelocity();

      if (Math.abs(velocityY) > mMinimumVelocity) {

        fling(velocityX, -velocityY);
      }
 当y方向的速度达到一个系统提供定值的时候我们调用fling方法
 public void fling(int velocityX, int velocityY) {
 
// getScrollX、getScrollY得到View移动到的坐标距离原坐标的差值,负值顺着x、y轴方向移动,正值反之。
// getCurrY获取mScroller当前竖直滚动的位置
  mScroll.fling(0, getScrollY(), velocityX, velocityY, 0, 0, 0,
        mTopViewHeight);
  invalidate();
}

其中invalidate会调用draw方法,紧接着draw会调用computeScroll,所以在computeScroll调用invalidate如果没有条件限制的话,其实就是进入了一个死循环。
@Override
public void computeScroll() {

   if (mScroll.computeScrollOffset()) {

      Log.e("tag", "computeScroll");
     scrollTo(mScroll.getCurrX(), mScroll.getCurrY());
     invalidate();
   }
}

当scroller还没有停的时候不断的移动,一个动画就这样实现了。至于getScrollX这个返回值是撒?引用网友的一个图片吧?通俗易懂~~

android自定义系列(七)–仿大街网个人中心页面
当然,这里还有listview高度的调整,这里不在讨论的范畴,具体的看代码。
最后奉上代码~~
http://download.csdn.net/detail/qq815034762/9388068
有bug欢迎提出~~~
这是我建的群,有兴趣的可以加:207678498

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值