Android开发滑动到顶部悬停效果

之前也出个微博悬停效果,但是它里面是底部是viewpager的,还有它的自定义控件过于复杂。

这次写一个底部就一个recyclerview,算是改良版本

废话先来看下效果图,是不是你们要的。由于我找不到csdn博客上上传视频的地方,只能上传效果。

第一张:首屏画面

Android开发滑动到顶部悬停效果_第1张图片

第二张:滑动画面

Android开发滑动到顶部悬停效果_第2张图片

三张:滑动留言精选处悬停效果

Android开发滑动到顶部悬停效果_第3张图片

希望大家能看懂三张图,联想到其中的操作,第三张图的发表感想按钮是显示隐藏弄出来了的,它和留言精选同在一个父控件中的。

这个应该是处理事件分发应用的最好体现了,能自己搞出来的,事件分发就过关了。不过我也是在别人的基础上改的,嘿嘿。

核心代码: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引用部分:





    
        

        

            

            

                

                    

                    

                    

                    

                    

                        

                        

                        

                        

                        
                        
                        

                            

                            
                        

                        
                        
                        

                            
                        


                    
                



            



            

注意看使用@id定义的控件,它需要你在value文件下进行定义。因为在自定义控件有用到。

为啥没有详细的解读自定义控件呢,因为我也还没研究的很透切,但是我基本会改了的。遵循思想是什么时候什么控件获取事件。还有自己去写一个问题很多的。

在Activity中的代码为啥没给出,我觉得没必要。

有问题的请留言或者加我QQ:893151960



你可能感兴趣的:(android开发日记)