[Android] 모조미단 선택 도시 인터페이스, 위챗 통신록 인터페이스를 신속하게 실현

15663 단어
개술
본문은 이 시리즈의 세 번째 편으로 의외의 사고가 발생하지 않아도 종결편이다.재구성된 컨트롤러를 사용하면 시장에 색인 내비게이션을 가지고 그룹을 나누는 목록 인터페이스를 신속하게 실현할 수 있기 때문이다.앞의 두 편에서 우리는 0부터 한 걸음 한 걸음 위챗 통신록을 모방하고 배고프면 식사 선택 인터페이스를 실현했다.(첫 번째 문장은 나를 찍고 두 번째 문장은 나를 찍는다) 이 문장은 종결편으로 앞의 문장에 비해 주로 다음과 같은 내용과 관련된다.
  • 인터럽트 그룹을 재구성하여 Title Item Decoration을 Suspension Decoration으로 바꾸고 데이터 원본은 ISuspension Interface 인터페이스에 의존한다.
  • 색인 내비게이션을 재구성하여 인덱스Bar가 데이터 원본에 대한 조작, 예를 들어 정렬, 병음 돌리기 등을 분리하여 인터페이스 IIndexBarDataHelper로 통신한다.
  • N다형제가 나에게 메시지를 남기고 QQ를 추가해서 물었다. 미국 단체가 도시 목록 페이지를 선택하는 방법을 어떻게 실현하는가
  • 중단 없이 그룹화된 HeaderView 추가
  • 코드 전송문: 마음에 들면 스타를 눌러주세요.대단히 감사합니다https://github.com/mcxtzhang/SuspensionIndexBar
    낡은 관습, 먼저 위의 그림:.
    미단 은 도시 인터페이스 를 선택하여 먼저 Body 주체 데이터 를 갱신하고, 다시 방향 을 정하여 머리 데이터 를 갱신한다
    위챗 통신록 인터페이스
    내 다른 라이브러리 조립에 맞게 (Suspension Index Bar + Swipe Menu Layout)
    (SwipeDelMenuLayout : https://github.com/mcxtzhang/SwipeDelMenuLayout)
    본고는 먼저 예를 들어 어떻게 쓰는지 설명하고 그 중에서 언급된 재구성 부분을 설명할 것이다.만약 불분명한 사람이 있다면 먼저 (첫 번째 스탬프, 두 번째 스탬프)를 보고 데모를 다운로드하고 코드를 보면서 읽는 것이 효과가 더욱 좋습니다.
    전재는 출처를 표시하십시오:http://www.jianshu.com/p/813e2f7a9e51본문은 다음과 같다. [장욱동의]http://www.jianshu.com/users/8e91ff99b072/latest_articles) 코드 전송문: 마음에 들면 스타를 눌러라.대단히 감사합니다https://github.com/mcxtzhang/SuspensionIndexBar
    위챗 통신록 인터페이스 쓰기
    먼저 간단한 용법에서 볼 때 위챗 통신록 인터페이스는 일반적인 **분조 정지 & 인덱스 내비게이션 **의 목록과 비교하면 다음과 같다.
  • HeaderView 4개 추가
  • 이러한 HeaderView 레이아웃은 벌크 Item과 동일
  • 이들 HeaderView는 그룹 스톱 title 없음
  • 이 HeaderView는 색인 타이틀 사용자 정의 그룹
  • 실현: HeaderView는 본 논문의 중점이 아니라 마음대로 실현한다.내가 쓴 것은 내가 전에 쓴 것으로 나를 찔렀다
    배치와 바디 Item 일치
    레이아웃이 일치하기 때문에 우리는 주체 Item의 Bean을 사용하고 시티를 해당하는 데이터로 설정하면 된다. 예를 들어'새로운 친구':
    public class CityBean extends BaseIndexPinyinBean {
        private String city;//    
    

    그룹 정지 없음
    그룹 정지 해제, 다시 쓰기 isShowSuspension() 방법을false로 되돌려야 합니다.
    인덱스 타이틀 사용자 정의
    색인 타이틀이 일치하고 사용자 정의가 필요합니다.네 개의 머리의 빈 호출 setBaseIndexTag() 방법은 set 사용자 정의 타이틀과 일치하면 됩니다.
            mDatas.add((CityBean) new CityBean("    ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP));
            mDatas.add((CityBean) new CityBean("  ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP));
            mDatas.add((CityBean) new CityBean("  ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP));
            mDatas.add((CityBean) new CityBean("   ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP));
    

    핵심 코드:CityBean에 필드 도입isTop
    public class CityBean extends BaseIndexPinyinBean {
        private String city;//    
        private boolean isTop;//                  
        ...
        @Override
        public String getTarget() {
            return city;
        }
        @Override
        public boolean isNeedToPinyin() {
            return !isTop;
        }
        @Override
        public boolean isShowSuspension() {
            return !isTop;
        }
    }
    

    초기화:
            mRv.addItemDecoration(mDecoration = new SuspensionDecoration(this, mDatas));
            //indexbar   
            mIndexBar.setmPressedShowTextView(mTvSideBarHint)//  HintTextView
                    .setNeedRealIndex(true)//         
                    .setmLayoutManager(mManager);//  RecyclerView LayoutManager
    

    데이터 로드:
            mDatas = new ArrayList<>();
            //            IndexBar     ,
            //        ItemDecoration     titile
            mDatas.add((CityBean) new CityBean("    ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP));
            mDatas.add((CityBean) new CityBean("  ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP));
            mDatas.add((CityBean) new CityBean("  ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP));
            mDatas.add((CityBean) new CityBean("   ").setTop(true).setBaseIndexTag(INDEX_STRING_TOP));
            for (int i = 0; i < data.length; i++) {
                CityBean cityBean = new CityBean();
                cityBean.setCity(data[i]);//      
                mDatas.add(cityBean);
            }
            ...
            mIndexBar.setmSourceDatas(mDatas)//    
                    .invalidate();
            mDecoration.setmDatas(mDatas);
    

    관련된 재구성 코드
    위에서 언급한 바와 같이 재구성 후SuspensionDecoration 데이터 원본에 의존하는 인터페이스는 ISuspensionInterface인데 다음과 같다.
    public interface ISuspensionInterface {
        //        title
        boolean isShowSuspension();
        //   title
        String getSuspensionTag();
    }
    
    BaseIndexBean 에서 실행되며, 기본적으로 정지되어 있으며, 그룹 타이틀과 IndexBar의 태그는 같습니다.
    public abstract class BaseIndexBean implements ISuspensionInterface {
        private String baseIndexTag;//     (          )
    
        @Override
        public String getSuspensionTag() {
            return baseIndexTag;
        }
    
        @Override
        public boolean isShowSuspension() {
            return true;
        }
    }
    
    
    BaseIndexPinyinBean류는 현재 다음과 같다.
    public abstract class BaseIndexPinyinBean extends BaseIndexBean {
        private String baseIndexPinyin;//     
        
        //          ,                     
        //             
        //           
        //        
        public boolean isNeedToPinyin() {
            return true;
        }
    
        //            
        public abstract String getTarget();
    
    }
    

    그래서 우리는 위챗의 그런 효과를 실현해야 한다. 다시 쓰기isShowSuspension()isNeedToPinyin() 두 가지 방법만 사용하고 setBaseIndexTag()tag를 직접 설정하면 된다.
    모조미단이 도시를 선택하다
    이 페이지는 여전히 매우 번거롭기 때문에 절차도 가장 많다.코드와 함께 데모와 라이브러리 주소를 읽는 것을 권장합니다.미단 선택 도시 목록 분석:
  • 주체 부분은 여전히 일반적인 **분조 정지 & 색인 내비게이션 **의 목록(미단은 정지 기능이 없음)이다.
  • 머리는 약간의 복잡한 HeaderView로 구성되어 있습니다.
  • 오른쪽 색인 표시줄에서 보듯이 포지셔닝, 최근, 핫한 이 세 가지 Item은 목록의 세 가지 HeaderView에 대응한다.
  • 맨 위에 있는 HeaderView는 그룹화할 필요도 없고 색인도 필요 없습니다.

  • 그러면 하나하나 실현한다.
    본체 부분
    간단합니다. 앞의 마지막 봉인(두 번째 편 스탬프)에 따라 만약에 주체 부분만 있다면 주체 부분의 자바빈BaseIndexPinyinBean을 계승하고 데이터를 정상적으로 구축하여 최종적으로 IndexBar와 SuspensionDecoration에 설정하면 됩니다.
    public class MeiTuanBean extends BaseIndexPinyinBean {
        private String city;//    
        ...
        @Override
        public String getTarget() {
            return city;
        }
    }
    

    머리에 약간의 HeaderViews
    여기는HeaderView를 통해 머리 레이아웃을 추가하든itemViewType을 통해 스스로 실현하든지, 핵심은itemViewType을 통해 하는 것이다.머리의 헤드뷰도 RecyclerView의 Item이라는 뜻이다.Item이면 그에 상응하는 JavaBean이 있어야 합니다.우리는 이 자바빈을 대상으로 각각 계승할 필요가 있다. BaseIndexPinyinBean구체적으로 머리 구조를 어떻게 실현하는지는 본고의 중점이 아니기 때문에 더 이상 군말하지 않는다. 데모에는 데모와 라이브러리 주소를 자세히 볼 수 있는 코드가 있다.
    정, 근, 열 세 개의 HeaderView 처리
    정, 근, 열 세 가지 HeaderView의 특징은 다음과 같습니다.
  • 오른쪽 내비게이션 인덱스의 타이틀은 사용자 정의이고 병음 자모가 아니면 정렬할 필요가 없습니다.
  • 정지 그룹의 타이틀은 오른쪽 내비게이션 인덱스의 타이틀과 다르면 정지 그룹의 타이틀도 사용자 정의가 필요합니다.

  • 방법: 그러나 RecyclerView의 Item인 이상 인터럽트 그룹, 색인 내비게이션 기능도 있다.그럼 상속BaseIndexPinyinBean해야 돼요.
  • 병음으로 전환할 필요가 없고 정렬하지 않으면 다시 쓰기isNeedToPinyin()는false를 되돌려주고 setBaseIndexTag(indexBarTag)를 오른쪽 색인에 값을 부여합니다.
  • 사용자 정의 정지 그룹의 타이틀이 필요하면 다시 쓰기 getSuspensionTag() 타이틀을 되돌려줍니다.
  • public class MeituanHeaderBean extends BaseIndexPinyinBean {
        private List cityList;
        //  ItemDecoration   Tag
        private String suspensionTag;
        
        public MeituanHeaderBean(List cityList, String suspensionTag, String indexBarTag) {
            this.cityList = cityList;
            this.suspensionTag = suspensionTag;
            this.setBaseIndexTag(indexBarTag);
        }
        
        @Override
        public String getTarget() {
            return null;
        }
    
        @Override
        public boolean isNeedToPinyin() {
            return false;
        }
    
        @Override
        public String getSuspensionTag() {
            return suspensionTag;
        }
    
    
    }
    
    private List mHeaderDatas;로 정, 근, 열 헤드 데이터 원본을 저장하고 최종적으로 IndexBarSuspensionDecoration에 설정해야 한다.
            mHeaderDatas = new ArrayList<>();
            List locationCity = new ArrayList<>();
            locationCity.add("   ");
            mHeaderDatas.add(new MeituanHeaderBean(locationCity, "    ", " "));
            List recentCitys = new ArrayList<>();
            mHeaderDatas.add(new MeituanHeaderBean(recentCitys, "      ", " "));
            List hotCitys = new ArrayList<>();
            mHeaderDatas.add(new MeituanHeaderBean(hotCitys, "    ", " "));
    

    최상위 HeaderView
    맨 위에 있는 HeaderView는 오른쪽 색인이 필요하지 않으며, 그룹을 끊지 않습니다.그것은 단지 일반적인 HeaderView일 뿐이다.이런 수요에 대한 HeaderView는 그것들의 수량IndexBarSuspensionDecoration만 전달하면 된다.내부에서 나는 연결 좌표와 데이터 원본의 하표가 정확하다는 것을 보장하기 위해 이미 처리를 했다.
    mDecoration.setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size()));
    mIndexBar.setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size());
    

    여기에 헤드뷰 모두count=4를 사용하고 위의mHeaderDatassize=3을 빼면 오른쪽 색인도 필요 없고 그룹 헤더의 수량도 멈추지 않습니다.
    주체 데이터 집합과 헤더 데이터 집합을 합치다
    우리가 몇 걸음 전에 세 부분의 데이터 집합을 설계했는데 일부는 주체 데이터 집합이다.
        //       (    )
        private List mBodyDatas;
    

    두 번째 부분은 특성이 필요한 머리 데이터 집합입니다.
        //     
        private List mHeaderDatas;
    

    세 번째 부분은 특성이 필요 없는 데이터 집합입니다. 여기서 무시합니다.우리는 그것의count만 사용할 수 있다.우리는 첫 번째 부분과 두 번째 부분을 융합시켜 IndexBarSuspensionDecoration에 설치해야 한다.우리는 그것들의 공통된 기류BaseIndexPinyinBean를 이용하여 저장한다.핵심 코드는 다음과 같습니다.
        //   InexBar、ItemDecoration      
        private List mSourceDatas;
        
        mSourceDatas.addAll(mHeaderDatas);
        mSourceDatas.addAll(mBodyDatas);
    

    설정IndexBar:
            mIndexBar.setmPressedShowTextView(mTvSideBarHint)//  HintTextView
                    .setNeedRealIndex(true)//         
                    .setmLayoutManager(mManager)//  RecyclerView LayoutManager
                    .setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size());
                    .setmSourceDatas(mSourceDatas)//    
    

    설정SuspensionDecoration:
            mRv.addItemDecoration(new SuspensionDecoration(this, mSourceDatas)
                    .setHeaderViewCount(mHeaderAdapter.getHeaderViewCount() - mHeaderDatas.size()));
    

    효과도는 문장의 첫머리와 같다.
    핵심 코드
    여기서 한 가지 더 말씀드리자면, 정렬 기능을 IndexBarIIndexBarDataHelper 유형 변수에서 추출하여 mIndexBar.setmSourceDatas(mSourceDatas)할 때 자동으로 정렬합니다.수동으로 mIndexBar.getDataHelper().sortSourceDatas(mBodyDatas); 정렬을 호출할 수도 있다.본 절의 사례와 같이 먼저 바디데이터를 정렬한 다음sourceDatas에 통합하여 최종적으로 IndexBarSuspensionDecoration에 설정할 수 있다.예:
                    //   
                    mIndexBar.getDataHelper().sortSourceDatas(mBodyDatas);
                    mSourceDatas.addAll(mBodyDatas);
                    mIndexBar.setmSourceDatas(mSourceDatas)//    
                            .invalidate();
                    mDecoration.setmDatas(mSourceDatas);
    

    관련된 재구성 코드:
    앞서 언급한 데이터 구조의 재구성을 제외하고는 이전에 IndexBar에서 완성한 것도 다음과 같습니다.
  • 1 중국어를 병음으로 바꾸기
  • 2 indexTag 채우기
  • 3 정렬 소스 데이터 소스
  • 4 정렬된 소스 데이터 소스에 따라 ->indexBar의 데이터 소스
  • 인터페이스로 추출하여 IndexBar와 분리됨을 나타냅니다.
    /**
     *   :IndexBar          
     * 1        
     * 2   indexTag
     * 3       
     * 4           ->indexBar    
     *   :zhangxutong
     *   :[email protected]
     *   :http://blog.csdn.net/zxt0601
     *   : 2016/11/28.
     */
    
    public interface IIndexBarDataHelper {
        //  -》  
        IIndexBarDataHelper convert(List extends BaseIndexPinyinBean> data);
    
        //  ->tag
        IIndexBarDataHelper fillInexTag(List extends BaseIndexPinyinBean> data);
    
        //        (RecyclerView)
        IIndexBarDataHelper sortSourceDatas(List extends BaseIndexPinyinBean> datas);
    
        // IndexBar        (   ),  sortSourceDatas      
        IIndexBarDataHelper getSortedIndexDatas(List extends BaseIndexPinyinBean> sourceDatas, List datas);
    }
    

    IndexBar 내부에 있는 이 인터페이스의 변수는 다음 방법으로 요구 사항을 완료합니다.
     public IndexBar setmSourceDatas(List extends BaseIndexPinyinBean> mSourceDatas) {
            this.mSourceDatas = mSourceDatas;
            initSourceDatas();//         
            return this;
        }
    
    
        /**
         *         ,        
         *
         * @return
         */
        private void initSourceDatas() {
            //add by zhangxutong 2016 09 08 :          size 0   ,
            if (null == mSourceDatas || mSourceDatas.isEmpty()) {
                return;
            }
            if (!isSourceDatasAlreadySorted) {
                //  sourceDatas
                mDataHelper.sortSourceDatas(mSourceDatas);
            } else {
                //  ->  
                mDataHelper.convert(mSourceDatas);
                //  ->tag
                mDataHelper.fillInexTag(mSourceDatas);
            }
            if (isNeedRealIndex) {
                mDataHelper.getSortedIndexDatas(mSourceDatas, mIndexDatas);
                computeGapHeight();
            }
        }
    

    나는 sortSourceDatas() 실현에서 이미 convert(datas);fillInexTag(datas);를 호출했다
        @Override
        public IIndexBarDataHelper sortSourceDatas(List extends BaseIndexPinyinBean> datas) {
            if (null == datas || datas.isEmpty()) {
                return this;
            }
            convert(datas);
            fillInexTag(datas);
            //        
            Collections.sort(datas, new Comparator() {
                @Override
                public int compare(BaseIndexPinyinBean lhs, BaseIndexPinyinBean rhs) {
                    if (!lhs.isNeedToPinyin()) {
                        return 0;
                    } else if (!rhs.isNeedToPinyin()) {
                        return 0;
                    } else if (lhs.getBaseIndexTag().equals("#")) {
                        return 1;
                    } else if (rhs.getBaseIndexTag().equals("#")) {
                        return -1;
                    } else {
                        return lhs.getBaseIndexPinyin().compareTo(rhs.getBaseIndexPinyin());
                    }
                }
            });
            return this;
        }
    

    다음과 같은 변수로 정렬이 필요한지, 인덱스를 추출해야 하는지 여부를 제어합니다.
         //                   (      A B C   tag,       A B C   )
        private boolean isNeedRealIndex;
        //        ?
        private boolean isSourceDatasAlreadySorted;
    

    좋은 점
    이렇게 하면 내가 정렬하는 방식을 좋아하지 않거나 특수 문자의 색인을 사용자 정의하고 싶을 때, 지금은 '#' 이며, 다시 쓰기 IndexBarDataHelperImpl 클래스를 계승해서 완성할 수 있다는 장점이 있다.또는 아예 IIndexBarDataHelper 인터페이스를 실현하면 확장과 서로 다른 맞춤형 수요를 만족시킬 수 있으며 매번 IndexBar류를 수정하지 않아도 된다.
    총결산
    유연한 재작성ISuspensionInterface 인터페이스의 방법:
  • 스톱 타이틀
  • 을 표시해야 하는지 여부
  • 스톱된 titles
  • 유연한 재작성BaseIndexPinyinBean의 방법:
  • 병음으로 바뀔 필요가 있는지, 위챗 머리 같은 건 미단도 필요없고 필요없어
  • 위챗의 머리에 색인을 표시할 필요가 없음
  • 미단의 머리 색인 사용자 정의
  • 기본값은 필수입니다
  • .
  • isNeedToPinyin()false로 되돌아갈 때 수동setBaseIndexTag()인덱스바의 태그 값을 설정하는 것을 잊지 마세요.
  • IndexBarIIndexBarDataHelper는 모두 setHeaderViewCount(int headerViewCount) 방법을 제공하여 오른쪽 인덱스가 필요하지 않고 그룹을 끊는 HeaderView 수량도 설정하지 않았다.
    전재는 출처를 표시하십시오:http://www.jianshu.com/p/813e2f7a9e51본문은 다음과 같다. [장욱동의]http://www.jianshu.com/users/8e91ff99b072/latest_articles) 코드 전송문: 마음에 들면 스타를 눌러라.대단히 감사합니다https://github.com/mcxtzhang/SuspensionIndexBar

    좋은 웹페이지 즐겨찾기