悬浮效果StickScrollView

最近有个需要带悬浮效果,网上找了很久。最常用的是stikkyHeader,但是其用的是framlayout,并不符合我的需求!

今天偶尔发现StickScrollView,可以实现我的需求,在此记下。

public class StickScrollView extends ScrollView {

   private static final String STICKY = "sticky";
   private View mCurrentStickyView;
   private Drawable mShadowDrawable;
   private List<View> mStickyViews;
   private int mStickyViewTopOffset;
   private int defaultShadowHeight = 5;// 阴影高度
   private float density;
   private boolean redirectTouchToStickyView;

   /**
    * 当点击Sticky的时候,实现某些背景的渐变
    */
   private Runnable mInvalidataRunnable = new Runnable() {

      @Override
      public void run() {
         if (mCurrentStickyView != null) {
            int left = mCurrentStickyView.getLeft();
            int top = mCurrentStickyView.getTop();
            int right = mCurrentStickyView.getRight();
            int bottom = getScrollY()
                  + (mCurrentStickyView.getHeight() + mStickyViewTopOffset);

            invalidate(left, top, right, bottom);
         }

         postDelayed(this, 16);

      }
   };

   public StickScrollView(Context context, AttributeSet attrs) {
      this(context, attrs, 0);
   }

   public StickScrollView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
      mShadowDrawable = context.getResources().getDrawable(
            R.drawable.sticky_shadow_default);
      mStickyViews = new LinkedList<View>();
      density = context.getResources().getDisplayMetrics().density;
   }

   /**
    * 找到设置tagView
    * 
    * @param viewGroup
    */
   private void findViewByStickyTag(ViewGroup viewGroup) {
      int childCount = ((ViewGroup) viewGroup).getChildCount();
      for (int i = 0; i < childCount; i++) {
         View child = viewGroup.getChildAt(i);

         if (getStringTagForView(child).contains(STICKY)) {
            mStickyViews.add(child);
         }

         if (child instanceof ViewGroup) {
            findViewByStickyTag((ViewGroup) child);
         }
      }

   }

   @Override
   protected void onLayout(boolean changed, int l, int t, int r, int b) {
      super.onLayout(changed, l, t, r, b);
      if (changed) {
         findViewByStickyTag((ViewGroup) getChildAt(0));
      }
      showStickyView();
   }

   @Override
   protected void onScrollChanged(int l, int t, int oldl, int oldt) {
      super.onScrollChanged(l, t, oldl, oldt);
      showStickyView();
   }

   /**
       * 
       */
   private void showStickyView() {
      View curStickyView = null;
      View nextStickyView = null;

      for (View v : mStickyViews) {
         int topOffset = v.getTop() - getScrollY();

         if (topOffset <= 0) {
            if (curStickyView == null
                  || topOffset > curStickyView.getTop() - getScrollY()) {
               curStickyView = v;
            }
         } else {
            if (nextStickyView == null
                  || topOffset < nextStickyView.getTop() - getScrollY()) {
               nextStickyView = v;
            }
         }
      }

      if (curStickyView != null) {
         mStickyViewTopOffset = nextStickyView == null ? 0 : Math.min(
               0,
               nextStickyView.getTop() - getScrollY()
                     - curStickyView.getHeight());
         mCurrentStickyView = curStickyView;
         post(mInvalidataRunnable);
      } else {
         mCurrentStickyView = null;
         removeCallbacks(mInvalidataRunnable);

      }

   }

   private String getStringTagForView(View v) {
      Object tag = v.getTag();
      return String.valueOf(tag);
   }

   /**
    * sticky画出来
    */
   @Override
   protected void dispatchDraw(Canvas canvas) {
      super.dispatchDraw(canvas);
      if (mCurrentStickyView != null) {
         // 先保存起来
         canvas.save();
         // 将坐标原点移动到(0, getScrollY() + mStickyViewTopOffset)
         canvas.translate(0, getScrollY() + mStickyViewTopOffset);

         if (mShadowDrawable != null) {
            int left = 0;
            int top = mCurrentStickyView.getHeight() + mStickyViewTopOffset;
            int right = mCurrentStickyView.getWidth();
            int bottom = top + (int) (density * defaultShadowHeight + 0.5f);
            mShadowDrawable.setBounds(left, top, right, bottom);
            mShadowDrawable.draw(canvas);
         }

         canvas.clipRect(0, mStickyViewTopOffset,
               mCurrentStickyView.getWidth(),
               mCurrentStickyView.getHeight());

         mCurrentStickyView.draw(canvas);

         // 重置坐标原点参数
         canvas.restore();
      }
   }

   @Override
   public boolean dispatchTouchEvent(MotionEvent ev) {
      if (ev.getAction() == MotionEvent.ACTION_DOWN) {
         redirectTouchToStickyView = true;
      }

      if (redirectTouchToStickyView) {
         redirectTouchToStickyView = mCurrentStickyView != null;

         if (redirectTouchToStickyView) {
            redirectTouchToStickyView = ev.getY() <= (mCurrentStickyView
                  .getHeight() + mStickyViewTopOffset)
                  && ev.getX() >= mCurrentStickyView.getLeft()
                  && ev.getX() <= mCurrentStickyView.getRight();
         }
      }

      if (redirectTouchToStickyView) {
         ev.offsetLocation(0, -1 * ((getScrollY() + mStickyViewTopOffset) - mCurrentStickyView.getTop()));
      }
      return super.dispatchTouchEvent(ev);
   }

   private boolean hasNotDoneActionDown = true;

   @SuppressLint("Recycle")
   @Override
   public boolean onTouchEvent(MotionEvent ev) {
      if (redirectTouchToStickyView) {
         ev.offsetLocation(0,
               ((getScrollY() + mStickyViewTopOffset) - mCurrentStickyView
                     .getTop()));
      }

      if (ev.getAction() == MotionEvent.ACTION_DOWN) {
         hasNotDoneActionDown = false;
      }

      if (hasNotDoneActionDown) {
         MotionEvent down = MotionEvent.obtain(ev);
         down.setAction(MotionEvent.ACTION_DOWN);
         super.onTouchEvent(down);
         hasNotDoneActionDown = false;
      }

      if (ev.getAction() == MotionEvent.ACTION_UP
            || ev.getAction() == MotionEvent.ACTION_CANCEL) {
         hasNotDoneActionDown = true;
      }
      return super.onTouchEvent(ev);
   }

}

这个类是通过过滤tag 来标识你是否需要悬浮,故在布局文件中需要设置tag,代码如下

android:tag="sticky"
哪一个控件需要悬浮,则给哪个设置以上属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值