Android 모방 eleme 주문 페이지 2 단계 연동 목록

이번 주말 에 배달 을 많이 시 켰 으 니 배 고 프 세 요?먼저 그림 을 올 려 보 세 요.이런 주문 페이지 는 낯 이 익 지 않 습 니까?
这里写图片描述
오른쪽 listview 를 그룹 으로 나 눈 후 왼쪽 Tab 페이지 에 색인 을 만 듭 니 다.직접 내 비게 이 션 할 수 있어 서 편리 하지 않 아 요?관건 은 오른쪽 이 미 끄 러 지고 왼쪽 도 미 끄 러 지 는 것 이다.왼쪽 을 누 르 면 오른쪽 항목 도 찾 을 수 있 습 니 다.그것들 은 이러한 특수 한 상호작용 이 존재 한다.이러한 연동 효과 와 같이 흔히 볼 수 있 는 예 도 있 습 니 다.예 를 들 어 흔히 볼 수 있 는 toolbar+view Pager 의 연동 을 사 용 했 고 상하 구조 에 불과 합 니 다.
这里写图片描述
다시 평 가 를 보면 도시 선택 페이지 에 도 이런 연동 의 그림자 가 있 는데 조금 약 할 뿐이다.사 이 드 바 는 listview 를 색인 할 수 있 습 니 다.이것 은 최초 로 위 챗 친구 목록 에 나타 난 것 입 니 다.
这里写图片描述
주말 을 틈 타 나 도 하 나 를 훑 었 다.확장 성 으로 는 그 이상 의 모든 상황 에 맞 출 수 있 을 것 이다.링크 드 레이아웃 이 라 고 부 릅 니 다.효과 도 를 보 세 요.
这里写图片描述
나 는 오른쪽 을 5 개 조로 누 르 면 왼쪽 색인=오른쪽/5 를 볼 수 있다.
특징.
오른쪽 은 미 끄 러 지고 왼쪽 은 따라 움직인다.
왼쪽 은 경계 로 미 끄 러 지고 오른쪽 은 따라 움직인다.
왼쪽 tab 항목 을 누 르 면 오른쪽 슬라이딩 으로 해당 하 는 group 로 이동 합 니 다.
소스 코드
github 전송 문:https://github.com/fashare2015/LinkedScrollDemo
지식 점
하기 전에 먼저 지식 포 인 트 를 나열 하거나 우리 가 이 demo 에서 무엇 을 얻 을 수 있 는 지 말 해 보 세 요.
추상/인터페이스 프로 그래 밍
사용자 정의 뷰
에이전트 모드
UML 도표
listview&&recyclerview 의 세부 사항 복습
끝나 고 나 서 가장 큰 수확 을 거 둔 것 은 첫 번 째 로 인 터 페 이 스 를 향 해 프로 그래 밍 한 것 같다.사실 기능 을 완성 하 는 시간 은 절반 에 불과 하고 뒤의 시간 은 추상 적 이 고 재 구성 되 어 있다.아,한 걸음 에 도착 하 는 것 은 너무 어렵 습 니 다.아니면 구체 적 인 유형 을 솔직하게 쓰 고 기 류 를 뽑 는 것 이 좋 겠 습 니 다.
구상 하 다
UI 부분
LinkedLayout
할 일 은 서로 연 결 된 두 개의 목록 입 니 다.왼쪽 은 tab 페이지 이 고 오른쪽 은 content 페이지 입 니 다.먼저 상호작용 을 고려 하지 않 고 화면 을 만 듭 니 다.LinkedLayout 라 는 종 류 를 만들어 tab 과 content 를 재생 합 니 다.
这里写图片描述

public class LinkedLayout extends LinearLayout {
  private Context mContext;
  private BaseScrollableContainer mTabContainer;
  private BaseScrollableContainer mContentContainer;
  private SectionIndexer mSectionIndexer; //   
  ...
}
우 리 는 그것 으로 하여 금 LinearLayout 를 계승 하 게 하 였 으 며,동시에 두 개의 Container 의 동쪽 을 가지 게 하 였 으 며,또 하나의 하나님 의 대상 인 mContext 와 하나의 조별 용 Section Indexer 도 가지 게 하 였 다.
BaseScrollableContainer
우선 신경 쓰 지 마 세 요.주로 Container 두 개 를 보 세 요.이름 으로 볼 때 하 나 는 tab 페이지 이 고 하 나 는 content 페이지 입 니 다.헤헤.다 스크롤 할 수 있 으 니까 차라리 Base Scrollable Container 를 만들어 보 세 요.Container 라 고 이름 을 지 었 으 니 당연히 Fragment 에 게 경 의 를 표 하 는 거 죠.우 리 는 이 종 류 를 정의 합 니 다.
초보 적 으로 생각해 보면 mContext 하나,view Group 하나,그리고 Listener 가 있 잖 아 요.
这里写图片描述

public abstract class BaseScrollableContainer<VG extends ViewGroup> {
  protected Context mContext;
  public VG mViewGroup;
  protected RealOnScrollListener mRealOnScrollListener;
  private EventDispatcher mEventDispatcher;
  ...
}
우리 가 예상 한 것 과 차이 가 많 지 않 잖 아 요.mContext 컨 텍스트,mView Group 은 기본적으로 우리 의 두 개의 listview 를 대신 하 는 것 을 말 합 니 다.물론 저 는 나중에 toolbar+view pager 를 해 야 합 니 다.추상 에 의존 해 야 합 니 다.listview 를 직접 쓸 수 없습니다.나머지 두 개 는 Listener 입 니 다.우리 화면 이 잘 맞 으 면 상호작용 을 할 때 보 세 요.
UML 그림 이 좋 은 것 같 습 니 다.계승 과 의존 관 계 는 일목요연 합 니 다.
사용자 정의 View&&동적 레이아웃
자,이제 사용자 정의 view 코너 입 니 다.우 리 는 이미 링크 드 레이아웃 을 가지 고 있 습 니 다.이것 은 우리 의 activity 입 니 다.main.xml 레이아웃 코드:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <com.fashare.linkedscrolldemo.ui.LinkedLayout
    android:id="@+id/linked_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"/>
</RelativeLayout>
닦 으 면 없어 져 요?나머지 는 자바 코드 로 해 야 돼.링크 드 레이아웃 으로 돌아 가서 UI 를 배치 합 시다~:

public class LinkedLayout extends LinearLayout {
  ...
  private static final int MEASURE_BY_WEIGHT = 0;
  private static final float WEIGHT_TAB = 1;
  private static final float WEIGHT_CONTENT = 3;

  public void setContainers(BaseScrollableContainer tabContainer, BaseScrollableContainer contentContainer) {
    mTabContainer = tabContainer;
    mContentContainer = contentContainer;
    mTabContainer.setEventDispatcher(this);
    mContentContainer.setEventDispatcher(this);

    //    LayoutParams
    mTabContainer.mViewGroup.setLayoutParams(new LinearLayout.LayoutParams(
        MEASURE_BY_WEIGHT,
        ViewGroup.LayoutParams.WRAP_CONTENT,
        WEIGHT_TAB
    ));

    mContentContainer.mViewGroup.setLayoutParams(new LinearLayout.LayoutParams(
        MEASURE_BY_WEIGHT,
        ViewGroup.LayoutParams.MATCH_PARENT,
        WEIGHT_CONTENT
    ));

    this.addView(mTabContainer.mViewGroup);
    this.addView(mContentContainer.mViewGroup);
    this.setOrientation(HORIZONTAL);
  }
}
setContainers 를 만들어 서 우리 의 Container 에 주입 시 켰 습 니 다.안에 layot 와 같 습 니 다.height,layout_width,layout_weight,orientation 같은 거 낯 이 익 죠?xml 과 다 르 지 않 아 요.참고 로 우 리 는 weight 속성 으로 이 비율 1:3 을 제어 하 였 는데,줄곧 이 속성 이 비교적 신기 하 다 고 느 꼈 다.
ViewGroup 주입,사용자 정의 링크 드 레이아웃 사용
여기까지 링크 드 레이아웃 이 구성 되 어 있 습 니 다.각각 View Group 에 주입 하면 사용 할 수 있 습 니 다.여 기 는 각각 listview 를 tab 로 하고,recyclerview 를 content 로 합 니 다.상상력 에 한계 가 있어 서 사용 하 는 것 도 이 정도 컨트롤 인 것 같 아 요...............................................이 부분의 코드 는 매우 간단 해서 MainActivity 에 서 는 붙 이지 않 습 니 다.
하위 클래스 화 BaseScrollable Container
상식 적 으로 아래 는 기 류 를 실현 해 야 하지 않 겠 습 니까?앞의 MainActivity 에서 우 리 는 이렇게 실례 화 되 었 다.

mTabContainer = new ListViewTabContainer(this, mListView); 
mContentContainer = new RecyclerViewContentContainer(this, mRecyclerView);
이름 을 보 니 하 나 는 listview 가 채 워 진 tab 이 고 하 나 는 recyclerview 가 채 워 진 content 입 니 다.이 두 가지 종 류 를 먼저 실현 합 시다.그림 에서 볼 수 있 듯 이 각각 BaseScrollable Container 에 계승 되 고 LinkedLayout 가 가지 고 있 습 니 다.
这里写图片描述  
대화 부분
사용자 와 의 대화:OnScrollListener 와 프 록 시 모드
마침내 상호작용 부분 에 이 르 렀 다.미 끄 러 지 는 만큼 모니터 를 정의 하 는 것 이 빠 질 수 없다.그러나 귀 찮 은 것 은 listview 와 recyclerview 각자 의 OnScroll Listener 가 다르다 는 점 이다.이 럴 때 각자 실현 하면 귀 찮 고 지루 하 다.이렇게:

// RecyclerView
public class RecyclerViewContentContainer extends BaseScrollableContainer<RecyclerView> {
  ...
  @Override
  protected void setOnScrollListener() {
    mViewGroup.addOnScrollListener(new ProxyOnScrollListener());
  }

  private class ProxyOnScrollListener extends RecyclerView.OnScrollListener {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
      if(newState == RecyclerView.SCROLL_STATE_IDLE) {      //     
        1.      ...
      }else if(newState == RecyclerView.SCROLL_STATE_DRAGGING){  //     
        2.        ...
      }
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) { //   
      3.      ...
    }
  }
}

// ListView
public class ListViewTabContainer extends BaseScrollableContainer<ListView> {
  ...
  @Override
  protected void setOnScrollListener() {
    mViewGroup.setOnScrollListener(new ProxyOnScrollListener());
    ...
  }

  public class ProxyOnScrollListener implements AbsListView.OnScrollListener{
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
      if(scrollState == SCROLL_STATE_IDLE) {       //     
        1.      ...
      }else if(scrollState == SCROLL_STATE_TOUCH_SCROLL) //     
        2.        ...
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      3.      ...        //   
    }
  }
}
그럼 어떻게 해 야 할 까요?각자 의 OnScroll Listener 의 차이 가 매우 크 지만 자세히 살 펴 보면 많은 논리 가 비슷 하고 공유 할 수 있다 는 것 을 알 수 있 습 니 다.이때 마침 대리 모드 로 재 구성 할 수 있다.나 는 1,2,3 곳 의 논 리 를 추출 했다.추상 적 인 의미 에서 일치 하기 때문에 인터페이스 로 정리 할 수 있다.

public interface OnScrollListener {
  // tab     
  void onClick(int position);

  // 1.    
  void onScrollStart();

  // 2.    
  void onScrollStop();

  // 3.   onScrolled()
  void onScrolled();

  //      ,     onScrolled()
  void onScrolledByUser();

  //      scrollTo(),     onScrolled()
  void onScrolledByInvoked();
}
이와 동시에 RecyclerView 와 ListView 각자 의 감청 기 는 각각 대리 류 로 서 1,2,3 의 논 리 를 모두 어떤 접 판 협 에 게 맡 기 고 스스로 실현 할 필요 가 없 으 며 오히려 편안 하고 자유롭다.그림 에서 보 듯 이 그림 설명 을 쓰 겠 습 니 다.
그리고 이 접 판 협:RealOn Scroll Listener...
온순 한 클래스 답 게 OnScroll Listener 의 모든 인 터 페 이 스 를 솔직하게 연결 하고 두 개의 프 록 시 클래스 에 의 해 소지 되 어 있 습 니 다.(그림 에 그 려 지지 않 았 습 니 다.)
구체 적 으로 실현 되면 붙 이지 않 겠 습 니 다.여러분 은 소스 코드 를 내 려 보 셔 도 됩 니 다.여기 서 대충 분석 해 보면 세 명의 구성원 이 있다.

public class RealOnScrollListener implements OnScrollListener {
  public boolean isTouching = false; //       
  private int mCurPosition = 0;    //      
  private BaseViewGroupUtil<VG> mViewUtil; // ViewGroup    
  ...
}
isTouching:
왜 이 터치 상 태 를 유지 해 야 합 니까?이것 은 우리 의 효과 가 연동 되 기 때문이다.이것 은 비교적 싫 습 니 다.onScrolled()가 호출 되 었 을 때 사용자 가 미 끄 러 졌 는 지,아니면 다른 목록 에서 미 끄 러 졌 을 때의 연동 효 과 를 구분 할 수 없습니다.그럼 우 리 는 isTouching 상 태 를 기록 하면 이 두 가지 상황 을 구분 할 수 있 습 니 다.
isTouching 의 논 리 를 onScrollStart()와 onScrollStop()에 변경 합 니 다.
mCurPosition:
이것 은 설명 하기 쉽다.우 리 는 매번 미 끄 러 질 때마다 현재 위 치 를 기록 한 후에 다른 목록 에 연동 을 통지 해 야 한다.
이 논 리 는 onScrolled()안에 있 습 니 다.
mViewUtil:
논 리 를 간소화 하 는 데 사용 되 는 도구 라 이브 러 리scrollto(),setView Selected(),UpdatePosOnScrolled()등 방법 이 있 습 니 다.그림 과 같 습 니 다.
这里写图片描述  
두 Container 간 의 상호작용
이전 에는 모두 사용자 에 대한 상호작용 이 었 는데,마침내 연동 부분 에 이 르 렀 다.급 하 게 실현 하지 않 고 먼저 저 에 게 한 가지 질문 에 대답 하 세 요.제 가 하나의 Activity 에서 두 개의 Fragment 를 가지 고 있다 고 가정 하고 그들 사이 에 어떻게 통신 하 는 지 물 어보 세 요.
A 학우 가 큰 소리 로 말 했다.라디오 로.
B 학생:EventBus!!!
C 학생:나 RxBus 봐...
장난 치지 마...얌전 히 있어.실 용 Listener.분명히 우리 가 직면 한 것 은 같은 장면 이다.LinkedLayout=Activity,Container=Fragment。
시작 하기 전에 Listener 를 정의 하 세 요.두 가지 이름 을 지어 야 합 니 다.

/*
 *      
 */
public interface EventDispatcher {
  /**
   *     : fromView    pos    
   * @param pos
   * @param fromView
   */
  void dispatchItemSelectedEvent(int pos, View fromView);
}
/*
 *      
 */
public interface EventReceiver {
  /**
   *     :      newPos
   * @param newPos
   */
  void selectItem(int newPos);
}
그 다음 에 LinkedLayout 는 부모 급 요소 로 서 배포 자의 역할 이 고 EventDispatcher 를 실현 해 야 합 니 다.BaseScrollable Container 는 하위 요소 로 이 사건 을 받 아들 이 고 EventReceiver 를 실현 해 야 합 니 다.다음 유형 도 를 보십시오.
这里写图片描述
해당 실현 보기(EventReceiver):

public abstract class BaseScrollableContainer<VG extends ViewGroup>
    implements EventReceiver {
  protected RealOnScrollListener mRealOnScrollListener;
  private EventDispatcher mEventDispatcher; //      
  ...
  public void setEventDispatcher(EventDispatcher eventDispatcher) {
    mEventDispatcher = eventDispatcher;
  }
  //    mEventDispatcher,    LinkedLayout
  protected void dispatchItemSelectedEvent(int curPosition){
    if(mEventDispatcher != null)
      mEventDispatcher.dispatchItemSelectedEvent(curPosition, mViewGroup);
  }
  @Override
  public void selectItem(int newPos) {
    mRealOnScrollListener.selectItem(newPos);
  }
  // OnScrollListener:     
  public class RealOnScrollListener implements OnScrollListener {
    ...
    public void selectItem(int position){
      mCurPosition = position;
      Log.d("setitem", position + "");
      //           
      mViewUtil.smoothScrollTo(position);
//      if(mViewUtil.isVisiblePos(position))  // curSection    ,    
        mViewUtil.setViewSelected(position);
    }
    @Override
    public void onClick(int position) {
      isTouching = true;
      mViewUtil.setViewSelected(mCurPosition = position);
      dispatchItemSelectedEvent(position); //   tab,    
      isTouching = false;
    }
    ...
    @Override
    public void onScrolled() {
      mCurPosition = mViewUtil.updatePosOnScrolled(mCurPosition);
      if(isTouching)     //     ,         
        onScrolledByUser();
      else          //     ,        
        onScrolledByInvoked();
    }
    @Override
    public void onScrolledByUser() {
      dispatchItemSelectedEvent(mCurPosition);  //     ,         
    }
  }
}
다시 보기(EventDispatcher):

public class LinkedLayout extends LinearLayout implements EventDispatcher {
  private BaseScrollableContainer mTabContainer;
  private BaseScrollableContainer mContentContainer;
  private SectionIndexer mSectionIndexer; //     
  ...
  @Override
  public void dispatchItemSelectedEvent(int pos, View fromView) {
    if (fromView == mContentContainer.mViewGroup) { //    content,     tab
      int convertPos = mSectionIndexer.getSectionForPosition(pos);
      mTabContainer.selectItem(convertPos);
    } else {          //    tab,     content
      int convertPos = mSectionIndexer.getPositionForSection(pos);
      mContentContainer.selectItem(convertPos);
    }
  }
}
총결산
여기까지 통쾌 한 느낌 이 들 지 않 았 나 요?아무래도 대상 을 대상 으로 하 는 것 은 신앙 이 고 인 터 페 이 스 를 정의 한 후에 이 루어 지 는 것 이 편 하 다.
//TODO:전에 말씀 드 렸 듯 이 이 연동 은 통용 되 는 것 입 니 다.그 후에 시간 이 있 으 면 toolbar+view Pager 의 연결 을 계속 실현 할 것 입 니 다.
달걀
고 화질 무 코드 도표:(완전)
这里写图片描述

좋은 웹페이지 즐겨찾기