안 드 로 이 드 다단 계 연동 컨트롤 실현 사고 토론

최근 에 한 가지 수 요 는 다단 계 연동 데 이 터 를 선택 하 는 것 이다.데이터 등급 이 고정 되 지 않 고 5 급 일 수도 있 고 2 급 일 수도 있 으 며 구체 적 으로 사용자 등급 을 볼 수 있다.
그래서 다단 계 연동 선택 컨트롤 이 필요 합 니 다.인터넷 에서 검색 하거나 이 컨트롤 을 찾 았 습 니 다.Android-PickerView
이 컨트롤 은 3 급 이내 의 연동 에는 문제 가 없 지만 최대 3 급 까지 만 가능 하 다.
나 는 원래 의 기초 위 에서 약간의 확장 을 했 는데,주로 두 개의 picker 를 추가 했다
MultiWheelPickerView 는 데이터 동적 에 따라 여러 개의 롤러 를 생 성 할 수 있 으 며 두 개의 세 가지 옵션 에 국한 되 지 않 습 니 다.Dynamic WheelPickerView 도 동적 으로 생 성 되 지만 한 단계 한 단계 데 이 터 를 불 러 오고 롤러 를 추가 할 수 있 습 니 다.
사용 할 때 자신의 상황 에 따라 자바 빈 이 IWheel Item 이나 IDynamicWheel Item 을 실현 하도록 하면 됩 니 다.
제 생각 과 실현 을 기록 하고 공유 하 며 여러분 과 함께 더 좋 은 실현 방안 을 토론 하고 싶 습 니 다.

처음에는 얻 은 데이터 의 동태 적 인 생 성 롤러 에 따라 몇 단계 가 있 으 면 몇 개 를 생 성하 고 자동 으로 배열 하면 된다.
원본 코드 를 보 니 원래 의 Options PickerView 에 WheelView 세 개가 죽 었 기 때문에 최대 세 개 밖 에 안 된다.
WheelView 를 동적 으로 생 성 하려 면 죽 을 수 없고 데이터 에 따라 만 생 성 할 수 있 기 때문에 저 는 코드 를 사용 하여 WheelView 를 만 들 고 layot 레이아웃 의 고정 수량 을 사용 하지 않 습 니 다.
휠 뷰 부분 을 제외 한 나머지 부분 은 모두 원래 의 레이아웃 을 사용한다.
데 이 터 를 동적 으로 표시 하려 면 원래IPickerViewData를 사용 할 수 없 기 때문에 새로운IWheelItem을 사 용 했 습 니 다.

public interface IWheelItem {

  /**
   *
   * @return         
   */
  String getShowText();

  /**
   *
   * @return       
   */
  <T extends IWheelItem> List<T> getNextItems();

}
두 가지 방법 만 있 습 니 다.롤러 에 표시 할 데 이 터 를 되 돌려 줍 니 다.1 단 계 를 선택 하면 다음 단계 의 내용 을 자동 으로 가 져 옵 니 다.
이런 다단 계 연동 의 데 이 터 는 상하 관계 가 뚜렷 하 다.나 는 기본적으로 이런 구조 이 고 한 단계 에 한 단계 씩 연결 되 어 있다.
WheelView 에서 조정 을 했 어 요.

/**
   *          
   *
   * @param item data resource
   * @return         
   */
  private String getContentText(Object item) {
    if (item == null) {
      return "";
    } else if (item instanceof IPickerViewData) {
      return ((IPickerViewData) item).getPickerViewText();
    } else if (item instanceof Integer) {
      //             .
      return getFixNum((int) item);
    }else if (item instanceof IWheelItem){
      return ((IWheelItem)item).getShowText();
    }
    return item.toString();
  }
First of all,데이터 의 등급 을 확정 하고 등급 에 따라 WheelView 의 수량 을 생 성 합 니 다.

/**
   *      list    ,      
   *              
   * @param list   
   * @return     
   */
  private int getLevel(List<T> list) {
    int level = 0;
    if (list != null && list.size() > 0) {
      level = 1;
      int childLevel = 0;
      for (T code : list) {
        List<T> children =code.getNextItems();
        int temp = getLevel(children);
        if (temp > childLevel) {
          childLevel = temp;
        }
      }
      level += childLevel;
    }
    return level;
  }
저 는 LinearLayout 의 가로 배열 을 사용 하여 동적 으로 생 성 된 WheelView 를 탑재 합 니 다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:orientation="vertical">

  <include
    layout="@layout/include_pickerview_topbar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/pickerview_topbar_height" />

  <LinearLayout
    android:id="@+id/ll_multi_picker"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:gravity="center"
    android:minHeight="180dp"
    android:orientation="horizontal">
  </LinearLayout>
</LinearLayout>
주의:여기 서 문 제 는 롤러 가 많이 생 성 되면 붐 비 는 것 이다.
몇 개의 롤러 를 생 성 해 야 하 는 지 알 게 된 후 코드 생 성 은 LinearLayout 에 직접 추 가 됩 니 다.

int level =getLevel(wheelItems);
if (level > 0) {
  //     
  for (int i = 0; i < level; i++) {
    WheelView wheelView = generateWheel();
    mLlContainer.addView(wheelView);
  }
  //      ,       
  initWheel(wheelItems, 0);
}
WheelView 를 생 성 한 후 컨트롤 에 값 을 부여 합 니 다.첫 번 째 값 을 선택 한 값 으로 기본 값 으로 가 져 옵 니 다.
앞의 단계 가 선택 되면 다음 단계 의 데 이 터 를 가 져 와 다음 컨트롤 에 값 을 부여 합 니 다.이렇게 마지막 으로 돌아 갑 니 다.

protected void initWheel(List<T> list, int wheelIndex) {
    WheelView wheelView = (WheelView) mLlContainer.getChildAt(wheelIndex);
    if (null == wheelView) {
      Log.d(MultiWheelPickerView.class.getSimpleName(), "initWheel:       " + wheelIndex + " > " + mLlContainer.getChildCount());
      return;
    }
    if (null != list && list.size() > 0) {
      wheelView.setAdapter(new MultiWheelAdapter(list));
      wheelView.setCurrentItem(0);
      wheelView.setOnItemSelectedListener(new MultiWheelItemSelector(list, wheelIndex));
      //       ,      。
      T wheelItem = list.get(0);
      addToResult(wheelItem, wheelIndex);
      List<T> children = list.get(0).getNextItems();
      //   ,    
      wheelIndex++;
      initWheel(children, wheelIndex);
    }else{
      for (int i=wheelIndex;i<mLlContainer.getChildCount();i++){
        wheelView = (WheelView) mLlContainer.getChildAt(i);
        wheelView.setAdapter(new MultiWheelAdapter(null));
      }
    }
  }
선택 한 데이터 와 이벤트 에 대해 서 는 원래 와 마찬가지 로 하나의 형식 만 바 꾸 고 List 용 기 를 사용 합 니 다.
순서대로 선택 한 데 이 터 를 모두 안에 열거 하 였 습 니 다.논 리 는 다음 과 같 습 니 다.

protected void addToResult(T value, int index) {
    //          ,        
    int size = resultList.size();
    Log.d(MultiWheelPickerView.class.getSimpleName(), "addToResult: " + index + "-->" + value + "; size->" + size);
    //     ,       
    while (index < size) {
      resultList.remove(index);
      size = resultList.size();
    }
    //         ,       
    boolean isAddToResult =true;
    if (null!=listener){
    //                ,          ,   all,    “”
      isAddToResult = listener.isAddToResult(value);
    }
    if (isAddToResult) {
      resultList.add(value);
    }
    if (null!=listener){
      listener.onChange(resultList);
    }
  }
이렇게 조금 만 고치 면 동적 다단 계 관련 컨트롤 이 있 습 니 다.사용 할 때 자바 빈 이 IWheel Item 을 실현 하도록 하면 됩 니 다.
간단 한 사용 방식 은 다음 과 같다.

MultiWheelPickerView<CodeTable> fixedPickerView;

  private void fixedPicker() {
    if (null == fixedPickerView) {
      MultiWheelPickerBuilder<CodeTable> builder = new MultiWheelPickerBuilder<>(this,
          new MultiWheelSelectListener<CodeTable>() {
            @Override
            public void onChange(List<CodeTable> result) {
              //              
              showChange(result);
            }

            @Override
            public void onSelect(List<CodeTable> result) {
              //            
              StringBuffer buffer = new StringBuffer();
              int size = result.size();
              for (int i = 0; i < size; i++) {
                if (i != 0) {
                  buffer.append("->");
                }
                buffer.append(result.get(i).getShowText());
              }
              mTvResult.setText(buffer.toString());
            }

            @Override
            public boolean isAddToResult(CodeTable selectValue) {
              //                   
              return !selectValue.getCode().equalsIgnoreCase("all");
            }
          });
      fixedPickerView = builder.build();
      fixedPickerView.setTitleText("    ");
      fixedPickerView.setWheelItems(getPickerData());
    }
    fixedPickerView.show();
  }
다단 계 연동 을 실 현 했 지만 실제 사용 할 때 무시 할 수 없 는 문 제 를 발견 했다.데이터 가 너무 많 으 면 장시간 불 러 올 것 이다.성급 에서 마을 급 까지 수만 개의 기록 이 있 고 한 번 에 얻 으 면 체험 이 너무 나 쁘 고 무 너 질 위험 이 있다.
더 좋 은 방법 은 1 급 1 급 으로 데 이 터 를 얻 는 것 이다.성급 을 선택 한 다음 에 부하 직원 의 시 급 을 얻 고 롤러 디 스 플레이 를 추가 하 는 것 이다.시 급 을 선택 한 다음 에 현급 을 얻 는 것 이다.이런 유추 이다.
So,계속 변경.데이터 도 여러 번 얻 었 기 때문에 등급 을 정할 수 없 기 때문에 새로운 등급 이 있 을 때마다 새로운 WheelView 를 디 스 플레이 용기 에 추가 해 야 합 니 다.
데 이 터 를 선택 할 때 도 다음 단 계 를 불 러 올 필요 가 있 는 지 판단 해 야 한다.나의 수요 에서 어떤 것 은 마을 급 에 가 야 하고 어떤 것 은 현급 에 가 야 한다.
그래서 다음 단계 의 설정 을 불 러 올 지 여 부 는 데이터 인터페이스 에 놓 고 데이터 자체 가 판단 합 니 다.
IWheel Item 을 바탕 으로 IDynamic Wheel Item 을 확장 하 였 습 니 다.

public interface IDynamicWheelItem extends IWheelItem {
  /**
   * @return          
   */
  boolean isLoadNext() ;
}
그 다음 에 WheelView 를 생 성 하 는 데 수정 을 했 고 들 어 오 는 데이터 에 따라 생 성 되 었 습 니 다.
기본 값 으로 첫 번 째 항목 을 선 택 했 습 니 다.선택 할 수 있다 면 하위 데 이 터 를 계속 생 성하 거나 불 러 옵 니 다.

protected void generateWheel(List<T> data) {
    if (data != null && data.size() > 0) {
      //     wheel
      WheelView wheelView = generateWheel();
      wheelView.setAdapter(new ArrayWheelAdapter(data));
      mLlContainer.addView(wheelView);
      int level = mLlContainer.getChildCount() - 1;
      wheelView.setOnItemSelectedListener(new DynamicWheelItemSelector(data, level));
      T iWheelItem = data.get(0);
      addToResult(iWheelItem, level);
      if (canSelect(iWheelItem)) {
        List<T> nextItems = iWheelItem.getNextItems();
        if (null != nextItems && nextItems.size() > 0) {
          generateWheel(nextItems);
        } else {
          if (iWheelItem.isLoadNext()) {
            loadNext(iWheelItem, ++level);
          }
        }
      }

    }
  }
데 이 터 를 선택 한 후 롤러 값 도 수정 되 었 습 니 다.다음 데 이 터 를 불 러 올 지,기 존 데 이 터 를 불 러 올 지 여 부 를 판단 하 는 경우
후속 으로 데이터 가 없 는 경우 에 도 휠 뷰 를 제거 하지 않 았 다.데이터 가 없 으 면 제거 하고 좌우 로 뛰 는 상황 이 발생 합 니 다.

/**
   *     Wheel    
   *
   * @param current   
   * @param nextLevel     
   */
  private void setupChildWheel(T current, int nextLevel) {
    if (mLlContainer.getChildCount() == nextLevel) {
      if (current.isLoadNext()) { //     ,           
        loadNext(current, nextLevel);
      }
      return;
    }
    List<T> nextItems = current.getNextItems();
    //    wheel         ,         ,     view,        null
    WheelView wheelView = (WheelView) mLlContainer.getChildAt(nextLevel);
    if (null != nextItems && nextItems.size() > 0) {
      //   
      //  level ==count      
      if (wheelView == null) {
        wheelView = generateWheel();
      }
      wheelView.setAdapter(new ArrayWheelAdapter(nextItems));
      wheelView.setCurrentItem(0);
      wheelView.setOnItemSelectedListener(new DynamicWheelItemSelector(nextItems, nextLevel));
      T wheelItem = nextItems.get(0);
      addToResult(wheelItem, nextLevel);
      nextLevel++;
      if (canSelect(wheelItem)) {
        setupChildWheel(wheelItem, nextLevel);
      }else{ //         ,            
        for (int i = nextLevel; i < mLlContainer.getChildCount(); i++) {
          wheelView = (WheelView) mLlContainer.getChildAt(i);
          wheelView.setOnItemSelectedListener(null);
          wheelView.setAdapter(new MultiWheelAdapter(null));
        }
      }
    } else {
      //                。
      //         
      for (int i = nextLevel; i < mLlContainer.getChildCount(); i++) {
        wheelView = (WheelView) mLlContainer.getChildAt(i);
        wheelView.setOnItemSelectedListener(null);
        wheelView.setAdapter(new MultiWheelAdapter(null));
      }
      //    ,     
      if (canSelect(current)&&current.isLoadNext()) {
        loadNext(current, nextLevel);
      }
    }
  }
데 이 터 를 불 러 오 는 데 성공 한 후,데 이 터 를 대응 하 는 롤러 에 추가 해 야 합 니 다

public void appendWheel(List<T> list, int level) {
    WheelView wheelView = null;
    if (level < mLlContainer.getChildCount()) {
      wheelView = (WheelView) mLlContainer.getChildAt(level);
    } else {
      wheelView = generateWheel();
      if (null != list && list.size() > 0)
        mLlContainer.addView(wheelView);
    }
    if (null != list && list.size() > 0) {
      wheelView.setAdapter(new MultiWheelAdapter(list));
      wheelView.setCurrentItem(0);
      T codeTable = list.get(0);
      addToResult(codeTable,level);
      wheelView.setOnItemSelectedListener(new DynamicWheelItemSelector(list, level));
      if (canSelect(codeTable)) { //    ,    。
        //       
        level++;
        setupChildWheel(codeTable,level);
      }

    }
  }
이로써 고 쳤 으 니 이전 것 보다 두 가지 방법 을 더 내 놓 아 라.
디텍터 에 하급 자 를 불 러 오 는 방법 을 확장 했다.

public interface DynamicWheelSelectListener<T extends IDynamicWheelItem>extends MultiWheelSelectListener<T> {
  /**
   *         
   * @param item     
   * @param nextLevel       
   */
  void loadNextItems(T item, int nextLevel);
}
사용 방법 은 위의 MultiWheelPickerView 와 대동소이 합 니 다.

DynamicWheelPickerView<CodeTable> dynamicPickerView;
  private void dynamicPicker() {
    if (null == dynamicPickerView) {
      dynamicPickerView =new DynamicWheelPickerBuilder<CodeTable>(this,new DynamicWheelSelectListener<CodeTable>() {
        @Override
        public void loadNextItems(CodeTable item, int nextLevel) {
          //       ,      isLoadNext     false。
          List<CodeTable> child = getChild(random());
          item.setChildren(child);
          item.setLoadNext(false);
          //            ,nextLevel       。
          dynamicPickerView.appendWheel(child, nextLevel);
        }

        @Override
        public void onChange(List<CodeTable> result) {
          showChange(result);
        }

        @Override
        public void onSelect(List<CodeTable> result) {
          StringBuffer buffer = new StringBuffer();
          int size = result.size();
          for (int i = 0; i < size; i++) {
            if (i != 0) {
              buffer.append("->");
            }
            buffer.append(result.get(i).getShowText());
          }
          mTvResult.setText(buffer.toString());
        }

        @Override
        public boolean isAddToResult(CodeTable selectValue) {
          //  0       
          return !selectValue.getCode().equalsIgnoreCase("0");
        }
      })
          .build();
      dynamicPickerView.setTitleText("    ");
      dynamicPickerView.setWheelItems(getChild(random()));

    }
    dynamicPickerView.show();
  }
구체 적 인 용법 은 코드 를 볼 수 있 습 니 다.여기 있 습 니 다TestMultiWheelActivity
다른 생각:
  • 현재 LinearLayout 소 포 를 사용 하고 있 는 경우 RecyclerView 로 바 꿀 수 있 습 니까?한 줄 이 몇 개 를 초과 한 후에 줄 을 바 꾸 어 붐 비지 않도록 잘 제어 할 수 있 습 니까?
  • 현재 동태 적 으로 롤러 를 추가 할 때 딱딱 하 게 추가 되 어 애니메이션 의 부 드 러 운 과 도 를 최적화 시 켜 체험 하 는 것 이 좋 을 것 이다.
  • 현재 코드 를 여기에 두 었 습 니 다Android-PickerView
    저의 실현 방식 은 바로 이 렇 습 니 다.여러분 과 더 좋 은 방식 을 토론 할 수 있 기 를 바 랍 니 다.
    여기 서 안 드 로 이 드 다단 계 연동 컨트롤 의 실현 방향 에 대한 토론 을 상세 하 게 설명 하 는 글 은 여기까지 입 니 다.더 많은 안 드 로 이 드 다단 계 연동 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 우 리 를 많이 지지 해 주세요!

    좋은 웹페이지 즐겨찾기