之前也出个微博悬停效果,但是它里面是底部是viewpager的,还有它的自定义控件过于复杂。
这次写一个底部就一个recyclerview,算是改良版本。
废话先来看下效果图,是不是你们要的。由于我找不到csdn博客上上传视频的地方,只能上传效果。
第一张:首屏画面
第二张:滑动画面
第三张:滑动留言精选处悬停效果
希望大家能看懂三张图,联想到其中的操作,第三张图的发表感想按钮是显示隐藏弄出来了的,它和留言精选同在一个父控件中的。
这个应该是处理事件分发应用的最好体现了,能自己搞出来的,事件分发就过关了。不过我也是在别人的基础上改的,嘿嘿。
核心代码:LetterStickyNavLayout
public class LetterStickyNavLayout extends LinearLayout {
private ScrollListener scrollListener;
private Context mContext;
private View mTop;
private View mNav;
//private ViewPager mViewPager;
//private SwipeRefRecyclerView mSRRceylerView;
private LinearLayout llContent;
private int mTopViewHeight;
private ViewGroup mInnerScrollView;
private boolean isTopHidden = false;
private OverScroller mScroller;
private VelocityTracker mVelocityTracker;
private int mTouchSlop;
private int mMaximumVelocity, mMinimumVelocity;
private float mLastY;
private boolean mDragging;
private boolean isInControl = false;
private boolean isChange=false;
private int screenWidth;
public LetterStickyNavLayout(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.VERTICAL);
mContext = context;
mScroller = new OverScroller(context);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mMaximumVelocity = ViewConfiguration.get(context)
.getScaledMaximumFlingVelocity();
mMinimumVelocity = ViewConfiguration.get(context)
.getScaledMinimumFlingVelocity();
screenWidth=Utils.getScreenWidthPx(mContext);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mTop = findViewById(R.id.id_stickynavlayout_topview);
mNav = findViewById(R.id.id_stickynavlayout_indicator);
//View sfrView = findViewById(R.id.id_stickynavlayout_swiperefrecyclerview);
View llView = findViewById(R.id.id_stickynavlayout_content);
if (!(llView instanceof LinearLayout)) {
throw new RuntimeException(
"id_stickynavlayout_content show used by LinearLayout !");
}
// if (!(sfrView instanceof SwipeRefRecyclerView)) {
// throw new RuntimeException(
// "SwipeRefRecyclerView show used by SwipeRefRecyclerView !");
// }
//
// mSRRceylerView = (SwipeRefRecyclerView) sfrView;
llContent =(LinearLayout)llView;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
ViewGroup.LayoutParams params;
// if(mSRRceylerView != null && mSRRceylerView.getVisibility() == VISIBLE){
// params = mSRRceylerView.getLayoutParams();
// }else{
// params = llContent.getLayoutParams();
// }
params = llContent.getLayoutParams();
int height;
if(Utils.checkDeviceHasNavigationBar(mContext)){
height = getMeasuredHeight() - mNav.getMeasuredHeight() + Utils.dip2px(mContext, 34);
}else{
height = getMeasuredHeight() - mNav.getMeasuredHeight();
}
//int height = getMeasuredHeight() - mNav.getMeasuredHeight();
if (height >= screenWidth && !isChange) {
params.height = height;
isChange = true;
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mTopViewHeight = mTop.getMeasuredHeight() ;
LogUtils.i("mTopViewHeight",mTopViewHeight+"");
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
float y = ev.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastY = y;
break;
case MotionEvent.ACTION_MOVE:
float dy = y - mLastY;
getCurrentScrollView();
if(mInnerScrollView != null && mInnerScrollView.getVisibility()== View.VISIBLE && mInnerScrollView instanceof SwipeRefRecyclerView){
LogUtils.i("swi","exist");
SwipeRefRecyclerView mSRRceylerView = (SwipeRefRecyclerView) mInnerScrollView;
RecyclerView lv = mSRRceylerView.getRecyclerView();
View c = lv.getChildAt(0);
if (!isInControl && c != null && c.getTop() == 0 && isTopHidden
&& dy > 0) {
isInControl = true;
ev.setAction(MotionEvent.ACTION_CANCEL);
MotionEvent ev2 = MotionEvent.obtain(ev);
dispatchTouchEvent(ev);
ev2.setAction(MotionEvent.ACTION_DOWN);
return dispatchTouchEvent(ev2);
}
} else {
if (llContent != null) {
if (!isInControl && android.support.v4.view.ViewCompat.canScrollVertically(llContent, -1) && isTopHidden
&& dy > 0) {
isInControl = true;
ev.setAction(MotionEvent.ACTION_CANCEL);
MotionEvent ev2 = MotionEvent.obtain(ev);
dispatchTouchEvent(ev);
ev2.setAction(MotionEvent.ACTION_DOWN);
return dispatchTouchEvent(ev2);
}
}
}
break;
}
return super.dispatchTouchEvent(ev);
}
/**
*
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
float y = ev.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastY = y;
break;
case MotionEvent.ACTION_MOVE:
float dy = y - mLastY;
if (Math.abs(dy) > mTouchSlop) {
mDragging = true;
if(mInnerScrollView != null && mInnerScrollView.getVisibility()== View.VISIBLE && mInnerScrollView instanceof SwipeRefRecyclerView){
SwipeRefRecyclerView ptrlv = (SwipeRefRecyclerView) mInnerScrollView;
RecyclerView lv = ptrlv.getRecyclerView();
View c = lv.getChildAt(0);
// 如果topView没有隐藏
// 或sc的PullToRefreshListView在顶部�&& topView隐藏 && 下拉,则拦截
if (!isTopHidden || (c != null && c.getTop() == 0 && isTopHidden && dy > 0 )) {
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
mLastY = y;
return true;
}
} else {
if (llContent != null) {
if (!isTopHidden || (!android.support.v4.view.ViewCompat.canScrollVertically(llContent, -1) && isTopHidden && dy > 0)) {
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
mLastY = y;
return true;
}
}
}
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mDragging = false;
recycleVelocityTracker();
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(event);
int action = event.getAction();
float y = event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished())
mScroller.abortAnimation();
mLastY = y;
return true;
case MotionEvent.ACTION_MOVE:
float dy = y - mLastY;
Log.e("TAG", "dy = " + dy + " , y = " + y + " , mLastY = " + mLastY);
if (!mDragging && Math.abs(dy) > mTouchSlop) {
mDragging = true;
}
if (mDragging) {
scrollBy(0, (int) -dy);
// 如果topView隐藏,且上滑动时,则改变当前事件为ACTION_DOWN
if (getScrollY() == mTopViewHeight && dy < 0) {
event.setAction(MotionEvent.ACTION_DOWN);
dispatchTouchEvent(event);
isInControl = false;
}
}
mLastY = y;
break;
case MotionEvent.ACTION_CANCEL:
mDragging = false;
recycleVelocityTracker();
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);
}
recycleVelocityTracker();
break;
}
return super.onTouchEvent(event);
}
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;
scrollListener.scrollToTop(isTopHidden);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(0, mScroller.getCurrY());
invalidate();
}
}
private void initVelocityTrackerIfNotExists() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
}
private void recycleVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
private void getCurrentScrollView() {
if (llContent != null) {
mInnerScrollView = (ViewGroup) (llContent
.findViewById(R.id.id_stickynavlayout_swiperefrecyclerview));
}
}
/**
* 按钮滑动事件
*
* @param listener
*/
public void setOnScrollListener(ScrollListener listener) {
scrollListener = listener;
}
public interface ScrollListener {
public void scrollToTop(boolean flag);
}
}
上面代码中有三个要留意的地方也是怎样才能改为你项目的
mTop:头部内容(也就是会被滑走的顶部内容)
mNav:悬停部分
llContent:底部滑动的部分(我的recyclerview存在它里面,因为我项目要切换有没内容的底图),如果你项目仅仅有recyclerview的,你就要学会llContent里面干嘛,替换成你的recyclerview
下面是XML引用部分:
为啥没有详细的解读自定义控件呢,因为我也还没研究的很透切,但是我基本会改了的。遵循思想是什么时候什么控件获取事件。还有自己去写一个问题很多的。
在Activity中的代码为啥没给出,我觉得没必要。
有问题的请留言或者加我QQ:893151960