Android - 사용자 정의 - RecyclerView.LayoutManager

11314 단어 Android
어쩔 수 없이 Recycler View는 정말 강력하다. 예를 들어 무한 윤방 Banner, 슬라이딩 카드 등은 모두 Recycler View 버전이 있는데 그들은 어떻게 했을까?정답은RecyclerView 기반입니다.LayoutManager, RecyclerView를 사용자 정의할 수 있습니다.LayoutManager, 그리고RecyclerView 내부 Item의 위치와 크기를 우리가 원하는 효과에 도달하도록 제어합니다. 간단하게 하기 위해서는RecyclerView를 사용자 정의합니다.LayoutManager, LinearLayoutManager의 효과를 모방합니다.
전체 설정:
  • 1.사용자 정의 클래스 TestLayoutManager 상속 RecyclerView.LayoutManager, 추상적인 방법:
  • public class TestLayoutManager extends RecyclerView.LayoutManager {
    
        @Override
        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
            return null;
        }
    }
  • 2.generate Default LayoutParams()는 RecyclerView 서브item의 LayoutParameters입니다. 일반 소포 내용은 다음과 같습니다.
  •     @Override
        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
            return  new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        }
  • 3.관건:onLayoutchildren(Recycler View.Recycler recycler, Recycler View.State state) 방법을 다시 쓰고 Item을 지정한 위치에 따라 보기에 추가합니다. 사용자 정의 ViewGroup과 유사한 onLayout 방법:
  •     @Override
        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
            //    item,    
            if (getItemCount() <= 0) return;
            //   preLayout,preLayout        
            if (state.isPreLayout()) {
                return;
            }
            //     ,     View Detach ,   Scrap   
            detachAndScrapAttachedViews(recycler);
            //          
            int offsetY = 0;
            for (int i = 0; i < getItemCount(); i++) {
                //           
                View view = recycler.getViewForPosition(i);
                // View   RecyclerView 
                addView(view);
                measureChildWithMargins(view, 0, 0);
                int width = getDecoratedMeasuredWidth(view);
                int height = getDecoratedMeasuredHeight(view);
                //  , View  
                int left = (getWidth() - width) / 2;
                layoutDecorated(view, left, offsetY, getWidth() - left, offsetY + height);
                //          height
                offsetY += height;
            }
        }

    실행 효과:
  • 4.이 때 Item은 정상적으로 표시되지만 스크롤 이벤트에 응답할 수 없기 때문에 스크롤 이벤트를 처리하고 canScrollVertically () 및 scrollVerticallyBy () 방법을 다시 써야 합니다:
  •     @Override
        public boolean canScrollVertically() {
            return true;
        }
        @Override
        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
            offsetChildrenVertical(dy);
            return dy;
        }
  • 5.이때 Item은 스크롤할 수 있지만 두 가지 문제가 있습니다. a. 슬라이딩 방향은 제스처와 반대입니다. 슬라이딩은 경계 제한이 없습니다. 다음 코드를 편집하여 문제를 해결합니다.
  •     @Override
        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
            //        
            int travel = dy;
    
            //        
            if (verticalScrollOffset + dy < 0) {
                travel = -verticalScrollOffset;
            } else if (verticalScrollOffset + dy > totalHeight - getVerticalSpace()) {//        
                travel = totalHeight - getVerticalSpace() - verticalScrollOffset;
            }
    
            //         +travel
            verticalScrollOffset += travel;
    
            //       item
            offsetChildrenVertical(-travel);
            return travel;
        }
    
        /**
         *   RecyclerView           ,    padding    
         *
         * @return
         */
        private int getVerticalSpace() {
            return getHeight() - getPaddingBottom() - getPaddingTop();
        }

    아직 Item 캐시를 하지 않은 것 외에 기본적으로 LinearLayoutManager와 효과가 많이 떨어지지 않았다.
    전체 소스:
    /**
     * Created by Chao  2018/8/15 on 16:15
     * description
     */
    public class TestLayoutManager extends RecyclerView.LayoutManager {
        private int totalHeight = 0;
        private int verticalScrollOffset = 0;
    
        @Override
        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
            return  new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        }
    
        @Override
        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
            //    item,    
            if (getItemCount() <= 0) return;
            //   preLayout,preLayout        
            if (state.isPreLayout()) {
                return;
            }
            //     ,     View Detach ,   Scrap   
            detachAndScrapAttachedViews(recycler);
            //          
            int offsetY = 0;
            totalHeight = 0;
            for (int i = 0; i < getItemCount(); i++) {
                //           
                View view = recycler.getViewForPosition(i);
                // View   RecyclerView 
                addView(view);
                measureChildWithMargins(view, 0, 0);
                int width = getDecoratedMeasuredWidth(view);
                int height = getDecoratedMeasuredHeight(view);
                //  , View  
                int left = (getWidth() - width) / 2;
                layoutDecorated(view, left, offsetY, getWidth() - left, offsetY + height);
                //          height
                offsetY += height;
    
                totalHeight += height;
            }
        }
    
        @Override
        public boolean canScrollVertically() {
            return true;
        }
    
        @Override
        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
            //        
            int travel = dy;
    
            //        
            if (verticalScrollOffset + dy < 0) {
                travel = -verticalScrollOffset;
            } else if (verticalScrollOffset + dy > totalHeight - getVerticalSpace()) {//        
                travel = totalHeight - getVerticalSpace() - verticalScrollOffset;
            }
    
            //         +travel
            verticalScrollOffset += travel;
    
            //       item
            offsetChildrenVertical(-travel);
            return travel;
        }
    
        /**
         *   RecyclerView           ,    padding    
         *
         * @return
         */
        private int getVerticalSpace() {
            return getHeight() - getPaddingBottom() - getPaddingTop();
        }
    }

    좋은 웹페이지 즐겨찾기