精华内容
下载资源
问答
  • recyclerview滚动,滚动时如果头部仍在可见则先滚动LinearLayout直到头部消失,再开始滚动recyclerview。 思路:自定义LinearLayout实现NestedScrollingParent,getChildAt(0)获取头部, ...

    需求:LinearLayout内部包含一个头部和一个recyclerview。recyclerview可滚动,滚动时如果头部仍在可见则先滚动LinearLayout直到头部消失,再开始滚动recyclerview。

    思路:
    1.自定义LinearLayout实现NestedScrollingParent,getChildAt(0)获取头部,计算头部高度。将LinearLayout的高度设置为自身高度 + 头部高度(隐藏头部后仍完整显示recyclerview)。
    2.在child滑动时 ,优先进行linearLayout的滑动,待linearLayout滑动到顶部或者向下滑动距离为头部高度时不再消费滑动事件并交由child继续执行。
    3.为了使滑动在LinearLayout的任意区域都能滑动LinearLayout,所有child包括头部都需要实现NestedScrollingChild。或者使用NestedSrollView、Recyclerview这些已经实现NestedScrollingChild的控件。
    4.仅实现滑动事件在filing时会有卡顿,为了提升用户体验应当将filing的相关方法实现。

    实现:

    public class HideFirstViewNestedLinearLayout extends LinearLayout implements NestedScrollingParent {
    
        private View mHeader;
        private int mHeaderHeight;
        private boolean mIsNeedNestedScroll = false;
        private Scroller mScroller = new Scroller(getContext());
    
        public HideFirstViewNestedLinearLayout(Context context) {
            super(context);
        }
    
        public HideFirstViewNestedLinearLayout(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        public HideFirstViewNestedLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
            return true;
        }
    
        @Override
        public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
            super.onNestedPreScroll(target, dx, dy, consumed);
            //过滤横向的误操作
            if (Math.abs(dx) * 1.5 > Math.abs(dy)) {
                return;
            }
            //滑动距离不得超过头部高度
            boolean headerScrollUp = dy > 0 && getScrollY() < mHeaderHeight;
            //滑动距离不得小于0
            boolean headerScrollDown = dy < 0 && getScrollY() > 0 && !target.canScrollVertically(-1);
            if ((headerScrollUp || headerScrollDown) && isIsNeedNestedScroll()) {
                if (dy + getScrollY() > mHeaderHeight) {
                    dy = mHeaderHeight - getScrollY();
                }
                if (dy + getScrollY() < 0) {
                    dy = 0 - getScrollY();
                }
                scrollBy(0, dy);
                consumed[1] = dy;
            }
        }
    
        @Override
        public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
            //当垂直方向速率大于头部高度时,开始动画自动滑动到顶部或底部
            if (Math.abs(velocityY) > mHeaderHeight && isIsNeedNestedScroll()) {
                if (velocityY > 0) {
                    mScroller.startScroll(getScrollX(), getScrollY(), 0, mHeaderHeight - getScrollY());
                } else {
                    mScroller.startScroll(getScrollX(), getScrollY(), 0, 0 - getScrollY());
                }
                invalidate();
            }
            return super.onNestedPreFling(target, velocityX, velocityY);
        }
    
        @Override
        public void computeScroll() {
            super.computeScroll();
            if (mScroller.computeScrollOffset()) {
                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
                postInvalidate();
            }
        }
    
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            if (getChildCount() > 0) {
                mHeader = getChildAt(0);
            }
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            Log.d(getClass().toString(), "onSizeChanged: mHeaderHeight = " + mHeaderHeight);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            mHeader.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            mHeaderHeight = 0;
            if (mHeader.getLayoutParams() instanceof LinearLayout.LayoutParams) {
                LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mHeader.getLayoutParams();
                mHeaderHeight = mHeaderHeight + layoutParams.topMargin + layoutParams.bottomMargin;
            }
            mHeaderHeight = mHeaderHeight + mHeader.getMeasuredHeight();
            int totalHeight;
            if (mIsNeedNestedScroll) {
                totalHeight = MeasureSpec.getSize(heightMeasureSpec) + mHeader.getMeasuredHeight();
            } else {
                totalHeight = MeasureSpec.getSize(heightMeasureSpec);
            }
            int mode = MeasureSpec.getMode(heightMeasureSpec);
            super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(totalHeight, mode));
        }
    
        public boolean isIsNeedNestedScroll() {
            return mIsNeedNestedScroll;
        }
    
        public void setIsNeedNestedScroll(boolean mIsNeedNestedScroll) {
            this.mIsNeedNestedScroll = mIsNeedNestedScroll;
        }
    }
    
    
    展开全文
  • 所以,我们的目标就是自定义一个可滑动LinearLayout,并且设置它的子布局都向上移动一个自定义LinearLayout的高度 一、自定义控件的测量和布局 自定义LinearLayout,假设为MyPullDownLayout: public class M

    先看效果图:

    先来说说思路:我们把该页面分为两部分,分别是头部的抽屉布局(海洋色背景)和主内容布局(白色背景),这两部分的布局是呈线性关系,即抽屉在上,主页面在下,并且它们的父布局应该是一个可滑动的LinearLayout线性布局

    所以,我们的目标就是自定义一个可滑动的LinearLayout,并且设置它的子布局都向上移动一个自定义LinearLayout的高度

    一、自定义控件的测量和布局

    自定义LinearLayout,假设为MyPullDownLayout:

    public class MyPullDownLayout extends LinearLayout {
        public MyPullDownLayout(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    }
    

    我们先对子控件进行简单的测量:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //测量子控件的大小
        for(int i=0;i<getChildCount();i++){
            View view=getChildAt(i);
            measureChild(view,widthMeasureSpec,heightMeasureSpec);
        }
    }

    在onLayout中设置每一个子控件的位置:

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l,t, r, b);
        int height=getVerticalHeight();
        //设置子控件的位置
        for(int i=0;i<getChildCount();i++){
            View view=getChildAt(i);
            view.layout(view.getLeft(),view.getTop()-height,view.getRight(),view.getBottom()-height);
        }
    }
    
    private int getVerticalHeight(){
        return getHeight()-getPaddingBottom()-getPaddingTop();
    }

    int height = getVerticalHeight() 即为这个自定义控件的高度,并让每个子控件都向上移动一个height的高度

     二、自定义控件的滑动实现

    我们创建一个手势检测器(GestureDetector)来辅助我们滑动控件:

    private int currentPos=0;
    private GestureDetector detector=new GestureDetector(new GestureDetector.SimpleOnGestureListener(){
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                                float distanceX, float distanceY) {
            //相对滑动:Y方向滑动多少距离,view就跟着滑动多少距离
            //手指向上滑动
            if(e2.getY()<e1.getY()&&getScrollY()>=0){
                //滑到的y值超过0时,反弹回去
                if(getScrollY()>0)scrollBy(0,-getScrollY());
                //否则什么也不做
            }
            else if(getScrollY()<=0){
                //如果手指向下滑动并且没有超过抽屉页的滑动范围,就滑动页面
                if(!(e2.getY()>e1.getY()&&getScrollY()==-getVerticalHeight())){
                    scrollBy(0,(int)distanceY);
                    //手指向下滑动
                    if(e2.getY()>e1.getY())currentPos=getScrollY()/(getVerticalHeight()/4);
                    //手指向上滑动
                    else currentPos=getScrollY()/(4*getVerticalHeight()/5);
                    if(currentPos>0)currentPos=0;
                    if(currentPos<-1)currentPos=-1;
                }
            }
            return super.onScroll(e1,e2,distanceX,distanceY);
        }
    });
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //将event信息传给detector;
        detector.onTouchEvent(event);
    }
    private int getVerticalHeight(){
        return getHeight()-getPaddingBottom()-getPaddingTop();
    }

    getScrollY():y轴方向已经滑动的距离。如果在抽屉页,则getScrollY()为负数

    currentPos:手指离开屏幕后,控件所在的位置(抽屉页或者主页面)

    currentPos=getScrollY()/(getVerticalHeight()/4):只需滑动1/4控件高度的距离就可以自动滑动到抽屉页

    currentPos=getScrollY()/(4*getVerticalHeight()/5):只需滑动1-4/5=1/5控件高度的距离就可以自动滑动到主页面 

     创建Scorller对象来实现页面的自动滑动效果:

    private Scroller scroller;
    public MyPullDownLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init(){
        scroller=new Scroller(getContext());
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //将event信息传给detector;
        detector.onTouchEvent(event);
        switch (event.getAction()){
            case MotionEvent.ACTION_UP:
                //手指离开屏幕后开始自动滑动
                scroller.startScroll(0,getScrollY(),0,getVerticalHeight()*currentPos-getScrollY());
                invalidate();
                break;
        }
        return true;
    }
    
    @Override
    public void computeScroll() {
        if(scroller.computeScrollOffset()){
            scrollTo(0,scroller.getCurrY());
            postInvalidateDelayed(10);
        }
    }

    scroller.startScroll():前两个参数是x,y方向已经滑动的距离,后两个参数是x,y方向还需要滑动的距离

    computeScroll():利用scroller.getCurrY()每次滑动一点点距离,调用postInvalidateDelayed(10)后会回调该方法

    三、XML布局文件注意事项

     为了体现抽屉控件的宽高占整个父控件宽高的效果,需要把抽屉布局(Layout)的width和height设为match_parent。然后主页面布局部分就放在抽屉布局的下方,具体代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <com.myviewtext.MyPullDownLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:background="@mipmap/bg">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="50dp"
                android:text="蜀道之难,难于上青天!"
                android:textColor="@color/white"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="50dp"
                android:text="蚕丛及鱼凫,开国何茫然!"
                android:textColor="@color/white"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="50dp"
                android:text="尔来四万八千岁,不与秦塞通人烟。西当太白有鸟道,可以横绝峨眉巅。"
                android:textColor="@color/white"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="50dp"
                android:text="地崩山摧壮士死,然后天梯石栈相钩连。"
                android:textColor="@color/white"/>
        </LinearLayout>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="臣本布衣,躬耕南阳,苟全性命于乱世,不求闻达于诸侯。"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,谘臣以当世之事,由是感激,遂许先帝以驱驰。"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="后值倾覆,受任于败军之际,奉命于危难之间:尔来二十有一年矣。"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧虑,恐付托不效,以伤先帝之明;故五月渡泸,深入不毛。"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="今南方已定,甲兵已足,当奖帅三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。"/>
    </com.hualinfo.myviewtext.MyPullDownLayout>

    自定义LinearLayout完整代码如下:

    public class MyPullDownLayout extends LinearLayout {
        private int currentPos=0;
        private Scroller scroller;
        public MyPullDownLayout(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //测量子控件的大小
            for(int i=0;i<getChildCount();i++){
                View view=getChildAt(i);
                measureChild(view,widthMeasureSpec,heightMeasureSpec);
            }
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            super.onLayout(changed, l,t, r, b);
            int height=getVerticalHeight();
            //设置子控件的位置
            for(int i=0;i<getChildCount();i++){
                View view=getChildAt(i);
                view.layout(view.getLeft(),view.getTop()-height,view.getRight(),view.getBottom()-height);
            }
        }
    
        private void init(){
            scroller=new Scroller(getContext());
        }
    
        private GestureDetector detector=new GestureDetector(new GestureDetector.SimpleOnGestureListener(){
            public boolean onScroll(MotionEvent e1, MotionEvent e2,
                                    float distanceX, float distanceY) {
                //相对滑动:Y方向滑动多少距离,view就跟着滑动多少距离
                //手指向上滑动
                if(e2.getY()<e1.getY()&&getScrollY()>=0){
                    //滑到的y值超过0时,反弹回去
                    if(getScrollY()>0)scrollBy(0,-getScrollY());
                    //否则什么也不做
                }
                else if(getScrollY()<=0){
                    //如果手指向下滑动并且没有超过抽屉页的滑动范围,就滑动页面
                    if(!(e2.getY()>e1.getY()&&getScrollY()==-getVerticalHeight())){
                        scrollBy(0,(int)distanceY);
                        //手指向下滑动
                        if(e2.getY()>e1.getY())currentPos=getScrollY()/(getVerticalHeight()/4);
                        //手指向上滑动
                        else currentPos=getScrollY()/(4*getVerticalHeight()/5);
                        if(currentPos>0)currentPos=0;
                        if(currentPos < -1)currentPos=-1;
                    }
                }
                return super.onScroll(e1,e2,distanceX,distanceY);
            }
        });
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            //将event信息传给detector;
            detector.onTouchEvent(event);
            switch (event.getAction()){
                case MotionEvent.ACTION_UP:
                    scroller.startScroll(0,getScrollY(),0,getVerticalHeight()*currentPos-getScrollY());
                    invalidate();
                    break;
            }
            return true;
        }
    
        @Override
        public void computeScroll() {
            if(scroller.computeScrollOffset()){
                scrollTo(0,scroller.getCurrY());
                postInvalidateDelayed(10);
            }
        }
    
        private int getVerticalHeight(){
            return getHeight()-getPaddingBottom()-getPaddingTop();
        }
    }
    

    本篇到这里就结束,下一篇我们来解决该自定义Layout与RecyclerView滑动冲突的问题:

    https://blog.csdn.net/zz51233273/article/details/108355290

    展开全文
  • 本篇我们来解决上一篇的遗留问题:自定义LinearLayout与RecyclerView的滑动冲突。 没看过上一篇文章的,可以先去看一下:https://blog.csdn.net/zz51233273/article/details/108320445 先看效果图: 一、解决...

    本篇我们来解决上一篇的遗留问题:自定义LinearLayout与RecyclerView的滑动冲突。

    没看过上一篇文章的,可以先去看一下:https://blog.csdn.net/zz51233273/article/details/108320445

    先看效果图:

    一、解决思路

    当手指一开始滑动时,触摸事件会被传递给RecyclerView去处理。并且在滑动列表数据的时候,我们确实是想让RecyclerView去处理触摸事件。经过长时间尝试,我发现用onInterceptTouchEvent方法让LinearLayout拦截事件是很难实现图中的效果。所以我换了一种解决思路:重写RecyclerView的onTouchEvent方法

    我们不再去处理触摸的拦截事件,全部交由RecyclerView处理,并且当滑动到RecyclerView顶部并继续手指往下滑时,就手动调用LinearLayout的scrollTo或scrollBy来让它进行相应的滑动,而不是在LinearLayout的触摸事件里做逻辑处理。

    当我们滑到抽屉页面时,自然而然触摸事件就自动交给了自定义LinearLayout处理。

    二、代码解释

    下面我给出代码,并解释每一步的操作

    创建MyRecyclerView类并继承RecyclerView:

    public class MyRecyclerView extends RecyclerView {
        public MyRecyclerView(@NonNull Context context) {
            super(context);
        }
    
        public MyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        public MyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent e) {
            return super.onTouchEvent(e);
        }
    }
    

    因为在滑动的时候,RecyclerView需要提醒外界是否手指向下滑动或者滑动完毕,所以需要开放接口:

    public interface OnScroll{
        //向下滑动时回调
        float scrollPullDown(int dy);
        //手指离开屏幕时回调
        void eventUp(int dy);
    }
    private OnScroll onScroll;
    public void setOnScroll(OnScroll onScroll){
        this.onScroll=onScroll;
    }

    当手指向上滑动时,肯定是处在滑动列表数据的状态,我们不用去做处理。当下滑的时候,可能是在滑动列表,也有可能是在滑动LinearLayout,这里就需要去判断一下。下面我们重写RecyclerView的onTouchEvent方法:

    private float lastPosY,moveY;   //lastPosY:手指最后滑动到的y轴位置;moveY:手指总共滑动的垂直距离
    @Override
    public boolean onTouchEvent(MotionEvent e) {
        switch (e.getAction()){
            case MotionEvent.ACTION_DOWN:
                lastPosY=e.getY();
                moveY=0;
                break;
            case MotionEvent.ACTION_MOVE:
                //如果手指往下滑动
                if(lastPosY<e.getY()){
                    if(onScroll!=null){
                        moveY+=(e.getY()-lastPosY)/2;
                        moveY=onScroll.scrollPullDown((int)moveY);
                        lastPosY=e.getY();
                        if(moveY>0)return true;
                    }
                }
                lastPosY=e.getY();
                if(moveY>0)return true;
                break;
            case MotionEvent.ACTION_UP:
                if(onScroll!=null)
                    onScroll.eventUp((int)moveY);
                break;
        }
        return super.onTouchEvent(e);
    }

    lastPosY<e.getY():代表手指向下滑动

    (e.getY()-lastPosY)/2:减少每次滑动LinearLayout的距离,保证滑动的流畅性

    if(moveY>0)return true:防止在滑动LinearLayout的时候同时滑动列表,从而产生滑动时的抖动。

     现在我们已经把滑动信息传递给了外界,下面我们用Activity来获取该信息:

    private MyRecyclerView recyclerView;
    private MyPullDownLayout pullDownLayout;
    private LinearLayoutManager linearLayoutManager;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_pull_down);
        init();
    }
    
    private void init(){
        final List<String> list=new ArrayList<>();
        //......
        recyclerView=findViewById(R.id.recyclerview);
        recyclerView.setAdapter(new MyRecyclerViewAdapter(list));
        linearLayoutManager=new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setOnScroll(new MyRecyclerView.OnScroll() {
            @Override
            public float scrollPullDown(int dy) {
                return 0;
            }
            @Override
            public void eventUp(int dy) {
            }
        });
    }

    xml文件也给大家放一下:

    <?xml version="1.0" encoding="utf-8"?>
    <com.myviewtext.MyPullDownLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/pulldown_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:background="@mipmap/bg">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="50dp"
                android:text="蜀道之难,难于上青天!"
                android:textColor="@color/white"/>
        </LinearLayout>
        <com.utils.MyRecyclerView
            android:id="@+id/recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:clickable="true"/>
    </com.myviewtext.MyPullDownLayout>

    那么在Activity中要怎么判断是否需要滑动LinearLayout呢?其实很容易,如果RecyclerView列表的第一项完全显示并且手指还在往下滑,那么就需要滑动LinearLayout,代码如下(Activity类):

    private void init(){
        final List<String> list=new ArrayList<>();
        //......
        pullDownLayout=findViewById(R.id.pulldown_layout);
        recyclerView=findViewById(R.id.recyclerview);
        recyclerView.setAdapter(new MyRecyclerViewAdapter(list));
        linearLayoutManager=new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setOnScroll(new MyRecyclerView.OnScroll() {
            @Override
            public float scrollPullDown(int dy) {
                if(linearLayoutManager.findFirstCompletelyVisibleItemPosition()==0){
                    pullDownLayout.scrollY(dy);
                    return dy;
                }
                return 0;
            }
            @Override
            public void eventUp(int dy) {
                if(linearLayoutManager.findFirstVisibleItemPosition()==0){
                    pullDownLayout.scrollToPage(dy);
                }
            }
        });
    }

    linearLayoutManager.findFirstCompletelyVisibleItemPosition()==0:如果列表第一项完全显示

    linearLayoutManager.findFirstVisibleItemPosition()==0:如果列表第一项有显示

    我们再来看看pullDownLayout对象的scrollY和scrollToPage方法:

    public class MyPullDownLayout extends LinearLayout {
        private Scroller scroller;
        public MyPullDownLayout(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        private void init(){
            scroller=new Scroller(getContext());
        }
    
        //......
    
        @Override
        public void computeScroll() {
            if(scroller.computeScrollOffset()){
                scrollTo(0,scroller.getCurrY());
                postInvalidateDelayed(8);
            }
        }
    
        private int getVerticalHeight(){
            return getHeight()-getPaddingBottom()-getPaddingTop();
        }
    
        public void scrollY(int dy){
            scrollTo(0,-dy);
        }
    
        public void scrollToPage(int dy){
            if(dy<getVerticalHeight()/6){
                scroller.startScroll(0,getScrollY(),0,-getScrollY());
            }else{
                scroller.startScroll(0,getScrollY(),0,-getVerticalHeight()-getScrollY());
            }
            invalidate();
        }
    }
    

    dy<getVerticalHeight()/6:如果总共滑动的距离小于布局高度的1/6,则自动返回到RecyclerView所在页面,否则自动滑动到抽屉页面

    到这里,滑动冲突就解决了(虽然不是利用拦截的手段,但也是一种解决办法,而且效果也不错)


    下面是MyRecyclerView完整代码:

    public class MyRecyclerView extends RecyclerView {
        private float lastPosY,moveY;   //lastPosY:手指最后滑动到的y轴位置;moveY:手指总共滑动的垂直距离
        public MyRecyclerView(@NonNull Context context) {
            super(context);
        }
    
        public MyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        public MyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent e) {
            switch (e.getAction()){
                case MotionEvent.ACTION_DOWN:
                    lastPosY=e.getY();
                    moveY=0;
                    break;
                case MotionEvent.ACTION_MOVE:
                    //如果手指往下滑动
                    if(lastPosY<e.getY()){
                        if(onScroll!=null){
                            moveY+=(e.getY()-lastPosY)/2;
                            moveY=onScroll.scrollPullDown((int)moveY);
                            lastPosY=e.getY();
                            if(moveY>0)return true;
                        }
                    }
                    lastPosY=e.getY();
                    if(moveY>0)return true;
                    break;
                case MotionEvent.ACTION_UP:
                    if(onScroll!=null)
                        onScroll.eventUp((int)moveY);
                    break;
            }
            return super.onTouchEvent(e);
        }
    
        public interface OnScroll{
            //向下滑动时回调
            float scrollPullDown(int dy);
            //手指离开屏幕时回调
            void eventUp(int dy);
        }
        private OnScroll onScroll;
        public void setOnScroll(OnScroll onScroll){
            this.onScroll=onScroll;
        }
    }
    

    MyRecyclerViewAdapter代码:

    public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
        private List<String> list;
        public MyRecyclerViewAdapter(List<String> list){
            this.list=list;
        }
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list,parent,false);
            ViewHolder holder = new ViewHolder(view);
            return holder;
        }
    
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.tv.setText(list.get(position));
        }
    
        @Override
        public int getItemCount() {
            return list.size();
        }
    
        class ViewHolder extends RecyclerView.ViewHolder{
            TextView tv;
            public ViewHolder(@NonNull View view) {
                super(view);
                tv=view.findViewById(R.id.tv);
            }
        }
    }
    

    item_list布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            android:textColor="@color/black"
            android:background="@color/white"/>
    </LinearLayout>

     

    展开全文
  • 可以看到我们NestedScrollView里嵌套了LinearLayout,NestedScrollView无法滑动到底部,以至于看不到Button当我们去掉下面一行代码时就可以看到 app:layout_behavior="@string/appbar_scrolling_view_

    遇到的问题:

    我们都知道NestedScrollViewScrollView只能有一个直接子布局,所以当想展示多个View时就会想到用LinearLayout或其他布局嵌套的方式来实现,但实际使用遇到了问题,如图所示:
    在这里插入图片描述
    可以看到我们NestedScrollView里嵌套了LinearLayoutNestedScrollView无法滑动到底部,以至于看不到Button当我们去掉下面一行代码时就可以看到

    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    

    可是为了实现AppBarLayout的折叠效果,又必须加上,百度无效,群里没人帮,只能翻墙来看了

    解决方案

    试过度娘的为NestedScrollView加上android:fillViewport="true",说是LinearLayout的match_parent不好使,得重新计算,此方法我试过不可行

    最终解决方案为:NestedScrollView添加以下两行代码

    android:layout_gravity="fill_vertical"
    android:layout_marginBottom="?attr/actionBarSize"
    

    目的是以便它测量并释放丢失的底部,作者说这个是控件的原因,待修复
    来源StackOverflow

    总结

    日后搜索问题还是多看Stack Overflow吧,度娘太多赋值粘贴,群里也基本没人帮你,所以还是要培养自己独立解决问题的能力呀,加油哈哈

    展开全文
  • android LinearLayout横向滑动(记录)

    千次阅读 2018-11-30 14:11:52
    记录一下线性布动态添加textview横向滑动 数据及判断 public void data() { int width = 0; list = new ArrayList&lt;&gt;(); for (int i = 0; i &lt; 50; i++) { list.add("14223355");...
  • 带有滚动 ViewPager 和 LinearLayout滑动布局包含一些标记页面位置的点。 您可以通过自定义属性来控制它。 演示 设置 依赖项 { compile project(':slideLayout') } 如何使用 您可以设置是否自动播放、点颜色和...
  • LinearLayout实现水平滑动,左右滑动

    千次阅读 2015-12-30 17:25:30
    要做LinearLayout的左右滑动效果,以前知道垂直的可以在外面套一个scollview控件可以实现,本以为把linearLayout设成水平即可,结果发现太天真. 百度了一下只有垂直的答案,后面历经艰难险阻..看到一结果,用...
  • 子View占满全屏,屏幕外面的View宽高为0,需要自己重新测量一下 for (int i=0;i<getChildCount();i++){ View childView = getChildAt(i); measureChild(childView,widthMeasureSpec,heightMeasureSpec);...
  • 继承Linearlayout的Viewgroup可以左右流畅滑动切换,类似viewpage
  • 文章目录1 实现NestedScrollingParent2接口2 自定义...嵌套滑动事件传递过程如下图所示: 1 实现NestedScrollingParent2接口 自定义LinearLayout,实现NestedScrollingParent2接口,先让onStartNestedScrol...
  • 情况A:ScrollView-LinearLayout-LinearLayout 情况B:ScrollView-RelativeLayout-LinearLayout A,B情况,都会导致ScrollView的滚动条占用一定空间 只有将A,B情况的最后LinearLayout改成RelativeLayout,...
  • Listview 每个item里边有个linearlayout linearlayout动态添加了不定数量的照片 我要点击图片时放大点击的图片 这个事件要怎么写?
  • LinearLayout表格

    2015-11-23 09:55:24
    LinearLayout 生成表格,上下滑动、左右滑动多选
  • public class BCustomerLinearLayout extends LinearLayout implements View.OnTouchListener { private static final String TAG = "CustomerLinearLayout"; public OnGestureChangeListener listener; ...
  • Viewpager+LinearLayout实现带索引的滑动要实现的效果图:主布局文件content_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.
  • 动画的全过程多是用代码来控制的,含有中文注释 知识点:自定义ScrollView,LinearLayout 作用:有助于对自定义View,动画的深入理解 demo链接 http://download.csdn.net/detail/atsince/8269211

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,784
精华内容 14,713
关键字:

linearlayout可滑动