1、自定义滚动控件

@SuppressLint({ "HandlerLeak", "Recycle" })

public class FloatScrollView extends ScrollView {
private static final String STICKY = "sticky";
private View mCurrentStickyView;
private Drawable mShadowDrawable;
private List mStickyViews;
private int mStickyViewTopOffset;
private int defaultShadowHeight = 10;
private float density;
private boolean redirectTouchToStickyView;
//
private float mMarginTop;
private OnScrollListener onScrollListener;


/**
* 当点击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 FloatScrollView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}


public FloatScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// mShadowDrawable =
// context.getResources().getDrawable(R.drawable.sticky_shadow_default);
mStickyViews = new LinkedList();
density = context.getResources().getDisplayMetrics().density;
mMarginTop = context.getResources().getDimension(
R.dimen.actionbar_height);
}


/**
* 找到设置tag的View

* @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();
if (onScrollListener != null) {
onScrollListener.onScroll(getScrollY());
}
}


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


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


if (topOffset <= 0 + mMarginTop) {
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
+ mMarginTop);


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 + mMarginTop)
&& ev.getX() >= mCurrentStickyView.getLeft()
&& ev.getX() <= mCurrentStickyView.getRight();
}
}


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


private boolean hasNotDoneActionDown = true;


@Override
public boolean onTouchEvent(MotionEvent ev) {
if (redirectTouchToStickyView) {
ev.offsetLocation(
0,
((getScrollY() + mStickyViewTopOffset + mMarginTop) - 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);
}


public OnScrollListener getOnScrollListener() {
return onScrollListener;
}


public void setOnScrollListener(OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}


public interface OnScrollListener {
void onScroll(int scrollY);
}

}

2、使用方式:在布局的时候对需要悬浮的布局leyout设置标签tag="sticky";进行标记即可;同时注意这个边的marginTop是用来设置悬浮位置离上方的距离,如有渐变的导航栏时需要用到。


*备注:个人备忘录!

更多相关文章

  1. TextView 设置 Ellipsize 属性,但它不工作?
  2. Android(安卓)媒体:网络视频播放器的基本设计
  3. Android(安卓)强制横屏或竖屏设置
  4. Android(安卓)WebView ScrollBar设置
  5. Android实现网络音乐播放器
  6. 设置 Android(安卓)wifi连接 samples【转】
  7. android 设置APN
  8. 设置android全屏的两种方式
  9. Linearlayout

随机推荐

  1. Button、选择框、日期、时间控件
  2. 【译】Android系统简介
  3. 【Android(安卓)Training视频系列】第4讲
  4. 免费学习android开发技术分享
  5. android:installLocation简析
  6. android 开发BUG
  7. android设定手机的显示模式,横竖屏,是否全
  8. Android多国语言文件夹命名
  9. Android——通知(Notification)
  10. Android当中的SeekBar与iOS中的UISlider