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 의 연결 을 계속 실현 할 것 입 니 다.
달걀
고 화질 무 코드 도표:(완전)
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.