package cn.qqtheme.framework.picker;
import android.app.Activity;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import cn.qqtheme.framework.entity.LinkageFirst;
import cn.qqtheme.framework.entity.LinkageSecond;
import cn.qqtheme.framework.entity.LinkageThird;
import cn.qqtheme.framework.util.LogUtils;
import cn.qqtheme.framework.widget.WheelView;
/**
* 两级、三级联动选择器。默认只初始化第一级数据,第二三级数据由联动获得。
* <p/>
* Author:李玉江[QQ:1032694760]
* DateTime:2016/5/6 20:34
* Builder:Android Studio
*
* @see Provider
* @see DataProvider
*/
public class LinkagePicker<Fst extends LinkageFirst<Snd>, Snd extends LinkageSecond<Trd>, Trd> extends WheelPicker {
protected Fst selectedFirstItem;
protected Snd selectedSecondItem;
protected Trd selectedThirdItem;
protected String firstLabel = "", secondLabel = "", thirdLabel = "";
protected int selectedFirstIndex = 0, selectedSecondIndex = 0, selectedThirdIndex = 0;
protected Provider provider;
protected float firstColumnWeight = 1.0f;//第一级显示的宽度比重
protected float secondColumnWeight = 1.0f;//第二级显示的宽度比重
protected float thirdColumnWeight = 1.0f;//第三级显示的宽度比重
private OnPickListener onPickListener;
private OnLinkageListener onLinkageListener;
private OnWheelListener onWheelListener;
private OnWheelLinkageListener onWheelLinkageListener;
public LinkagePicker(Activity activity) {
super(activity);
}
public LinkagePicker(Activity activity, DataProvider provider) {
super(activity);
this.provider = provider;
}
public LinkagePicker(Activity activity, Provider<Fst, Snd, Trd> provider) {
super(activity);
this.provider = provider;
}
/**
* 二级联动选择器构造函数
*
* @deprecated use {@link #LinkagePicker(Activity, Provider)} instead
*/
@Deprecated
public LinkagePicker(Activity activity, List<Fst> firstList, List<List<Snd>> secondList) {
this(activity, firstList, secondList, null);
}
/**
* 三级联动选择器构造函数
*
* @deprecated use {@link #LinkagePicker(Activity, Provider)} instead
*/
@Deprecated
public LinkagePicker(Activity activity, List<Fst> f, List<List<Snd>> s, List<List<List<Trd>>> t) {
super(activity);
this.provider = new DefaultDataProvider<>(f, s, t);
}
protected void setProvider(DataProvider provider) {
this.provider = provider;
}
protected void setProvider(Provider<Fst, Snd, Trd> provider) {
this.provider = provider;
}
public void setSelectedIndex(int firstIndex, int secondIndex) {
setSelectedIndex(firstIndex, secondIndex, 0);
}
public void setSelectedIndex(int firstIndex, int secondIndex, int thirdIndex) {
selectedFirstIndex = firstIndex;
selectedSecondIndex = secondIndex;
selectedThirdIndex = thirdIndex;
}
public void setSelectedItem(Fst fst, Snd snd) {
setSelectedItem(fst, snd, null);
}
public void setSelectedItem(Fst fst, Snd snd, Trd trd) {
if (null == provider) {
throw new IllegalArgumentException("please set data provider at first");
}
//noinspection unchecked
List<Fst> fsts = provider.initFirstData();
int i = 0;
for (Fst f : fsts) {
if (f.equals(fst)) {
selectedFirstIndex = i;
break;
} else if (f.getId().equals(fst.getId()) || f.getName().contains(fst.getName())) {
selectedFirstIndex = i;
break;
}
i++;
}
LogUtils.verbose("init select first: " + fst.getName() + ", index:" + selectedFirstIndex);
//noinspection unchecked
List<Snd> snds = provider.linkageSecondData(selectedFirstIndex);
int j = 0;
for (Snd s : snds) {
if (s.equals(snd)) {
selectedFirstIndex = i;
break;
} else if (s.getId().equals(snd.getId()) || s.getName().contains(snd.getName())) {
selectedSecondIndex = j;
break;
}
j++;
}
LogUtils.verbose("init select second: " + snd.getName() + ", index:" + selectedSecondIndex);
if (provider.isOnlyTwo()) {
return;//仅仅二级联动
}
//noinspection unchecked
List<Trd> trds = provider.linkageThirdData(selectedFirstIndex, selectedSecondIndex);
int k = 0;
for (Trd t : trds) {
if (t.equals(trd)) {
selectedThirdIndex = k;
break;
} else if (t instanceof LinkageThird) {
LinkageThird ltrd = (LinkageThird) trd;
LinkageThird lt = (LinkageThird) t;
if (lt.getId().equals(ltrd.getId()) || lt.getName().contains(ltrd.getName())) {
selectedThirdIndex = k;
break;
}
}
k++;
}
LogUtils.verbose("init select third: " + trd + ", index:" + selectedThirdIndex);
}
public void setLabel(String firstLabel, String secondLabel) {
setLabel(firstLabel, secondLabel, "");
}
public void setLabel(String firstLabel, String secondLabel, String thirdLabel) {
this.firstLabel = firstLabel;
this.secondLabel = secondLabel;
this.thirdLabel = thirdLabel;
}
public Fst getSelectedFirstItem() {
if (selectedFirstItem == null) {
//noinspection unchecked
selectedFirstItem = (Fst) provider.initFirstData().get(selectedFirstIndex);
}
return selectedFirstItem;
}
public Snd getSelectedSecondItem() {
if (selectedSecondItem == null) {
//noinspection unchecked
selectedSecondItem = (Snd) provider.linkageSecondData(selectedFirstIndex).get(selectedSecondIndex);
}
return selectedSecondItem;
}
public Trd getSelectedThirdItem() {
if (selectedThirdItem == null) {
List<Trd> thirdData = provider.linkageThirdData(selectedFirstIndex, selectedSecondIndex);
if (thirdData.size() > 0) {
selectedThirdItem = thirdData.get(selectedThirdIndex);
}
}
return selectedThirdItem;
}
public int getSelectedFirstIndex() {
return selectedFirstIndex;
}
public int getSelectedSecondIndex() {
return selectedSecondIndex;
}
public int getSelectedThirdIndex() {
return selectedThirdIndex;
}
/**
* 设置每列的宽度比例,将屏幕分为三列,每列范围为0.0~1.0,如0.3333表示约占宽度的三分之一。
*/
public void setColumnWeight(@FloatRange(from = 0, to = 1) float firstColumnWeight,
@FloatRange(from = 0, to = 1) float secondColumnWeight,
@FloatRange(from = 0, to = 1) float thirdColumnWeight) {
this.firstColumnWeight = firstColumnWeight;
this.secondColumnWeight = secondColumnWeight;
this.thirdColumnWeight = thirdColumnWeight;
}
/**
* 设置每列的宽度比例,将屏幕分为两列,每列范围为0.0~1.0,如0.5表示占宽度的一半。
*/
public void setColumnWeight(@FloatRange(from = 0, to = 1) float firstColumnWeight,
@FloatRange(from = 0, to = 1) float secondColumnWeight) {
this.firstColumnWeight = firstColumnWeight;
this.secondColumnWeight = secondColumnWeight;
this.thirdColumnWeight = 0;
}
/**
* 设置滑动过程数据联动监听器
*/
public void setOnWheelLinkageListener(OnWheelLinkageListener onWheelLinkageListener) {
this.onWheelLinkageListener = onWheelLinkageListener;
}
/**
* @deprecated use {@link #setOnWheelLinkageListener} instead
*/
@Deprecated
public void setOnWheelListener(OnWheelListener onWheelListener) {
this.onWheelListener = onWheelListener;
}
/**
* 设置完成选泽监听器
*/
public void setOnPickListener(OnPickListener<Fst, Snd, Trd> onPickListener) {
this.onPickListener = onPickListener;
}
/**
* 设置完成选泽监听器
*/
public void setOnStringPickListener(OnStringPickListener onStringPickListener) {
this.onPickListener = onStringPickListener;
}
/**
* @deprecated use {@link #setOnStringPickListener} instead
*/
@Deprecated
public void setOnLinkageListener(OnLinkageListener onLinkageListener) {
this.onLinkageListener = onLinkageListener;
}
@NonNull
@Override
protected View makeCenterView() {
if (null == provider) {
throw new IllegalArgumentException("please set data provider before make view");
}
LinearLayout layout = new LinearLayout(activity);
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setGravity(Gravity.CENTER);
final WheelView firstView = createWheelView();
firstView.setLayoutParams(new LinearLayout.LayoutParams(0, WRAP_CONTENT, firstColumnWeight));
//firstView.setLabel(firstLabel);
layout.addView(firstView);
if (!TextUtils.isEmpty(firstLabel)) {
TextView labelView = createLabelView();
labelView.setText(firstLabel);
layout.addView(labelView);
}
final WheelView secondView = createWheelView();
secondView.setLayoutParams(new LinearLayout.LayoutParams(0, WRAP_CONTENT, secondColumnWeight));
//secondView.setLabel(secondLabel);
layout.addView(secondView);
if (!TextUtils.isEmpty(secondLabel)) {
TextView labelView = createLabelView();
labelView.setText(secondLabel);
layout.addView(labelView);
}
final WheelView thirdView = createWheelView();
if (!provider.isOnlyTwo()) {
thirdView.setLayoutParams(new LinearLayout.LayoutParams(0, WRAP_CONTENT, thirdColumnWeight));
//thirdView.setLabel(thirdLabel);
layout.addView(thirdView);
if (!TextUtils.isEmpty(thirdLabel)) {
TextView labelView = createLabelView();
labelView.setText(thirdLabel);
layout.addView(labelView);
}
}
firstView.setItems(provider.initFirstData(), selectedFirstIndex);
firstView.setOnItemSelectListener(new WheelView.OnItemSelectListener() {
@Override
public void onSelected(int index) {
//noinspection unchecked
selectedFirstItem = (Fst) provider.initFirstData().get(index);
selectedFirstIndex = index;
LogUtils.verbose(this, "change second data after first wheeled");
selectedSecondIndex = 0;//重置第二级索引
selectedThirdIndex = 0;//重置第三级索引
//根据第一级数据获取第二级数据
//noinspection unchecked
List<Snd> snds = provider.linkageSecondData(selectedFirstIndex);
selectedSecondItem = snds.get(selectedSecondIndex);
secondView.setItems(snds, selectedSecondIndex);
if (!provider.isOnlyTwo()) {
//根据第二级数据获取第三级数据
//noinspection unchecked
List<Trd> trds = provider.linkageThirdData(selectedFirstIndex, selectedSecondIndex);
selectedThirdItem = trds.get(selectedThirdIndex);
thirdView.setItems(trds, selectedThirdIndex);
}
if (onWheelLinkageListener != null) {
onWheelLinkageListener.onLinkage(selectedFirstIndex, 0, 0);
}
if (onWheelListener != null) {
onWheelListener.onFirstWheeled(selectedFirstIndex, selectedFirstItem.getName());
}
}
});
secondView.setItems(provider.linkageSecondData(selectedFirstIndex), selectedSecondIndex);
secondView.setOnItemSelectListener(new WheelView.OnItemSelectListener() {
@Override
public void onSelected(int index) {
//noinspection unchecked
selectedSecondItem = (Snd) provider.linkageSecondData(selectedFirstIndex).get(index);
selectedSecondIndex = index;
if (!provider.isOnlyTwo()) {
LogUtils.verbose(this, "change third data after second wheeled");
selectedThirdIndex = 0;//重置第三级索引
//noinspection unchecked
List<Trd> trds = provider.linkageThirdData(selectedFirstIndex, selectedSecondIndex);
selectedThirdItem = trds.get(selectedThirdIndex);
//根据第二级数据获取第三级数据
thirdView.setItems(trds, selectedThirdIndex);
}
if (onWheelLinkageListener != null) {
onWheelLinkageListener.onLinkage(selectedFirstIndex, selectedSecondIndex, 0);
}
if (onWheelListener != null) {
onWheelListener.onSecondWheeled(selectedSecondIndex, selectedSecondItem.getName());
}
}
});
if (provider.isOnlyTwo()) {
return layout;//仅仅二级联动
}
thirdView.setItems(provider.linkageThirdData(selectedFirstIndex, selectedSecondIndex), selectedThirdIndex);
thirdView.setOnItemSelectListener(new WheelView.OnItemSelectListener() {
@Override
public void onSelected(int index) {
//noinspection unchecked
selectedThirdItem = (Trd) provider.linkageThirdData(selectedFirstIndex, selectedSecondIndex).get(index);
selectedThirdIndex = index;
if (onWheelLinkageListener != null) {
onWheelLinkageListener.onLinkage(selectedFirstIndex, selectedSecondIndex, selectedThirdIndex);
}
if (onWheelListener != null) {
String thirdName;
if (selectedThirdItem instanceof LinkageThird) {
thirdName = ((LinkageThird) selectedThirdItem).getName();
} else {
thirdName = selectedThirdItem.toString();
}
onWheelListener.onThirdWheeled(selectedThirdIndex, thirdName);
}
}
});
return layout;
}
@Override
public void onSubmit() {
Fst fst = getSelectedFirstItem();
Snd snd = getSelectedSecondItem();
Trd trd = getSelectedThirdItem();
if (provider.isOnlyTwo()) {
if (onPickListener != null) {
//noinspection unchecked
onPickListener.onPicked(fst, snd, null);
}
if (onLinkageListener != null) {
onLinkageListener.onPicked(fst.getName(), snd.getName(), null);
}
} else {
if (onPickListener != null) {
//noinspection unchecked
onPickListener.onPicked(fst, snd, trd);
}
if (onLinkageListener != null) {
String thirdName;
if (trd instanceof LinkageThird) {
thirdName = ((LinkageThird) trd).getName();
} else {
thirdName = trd.toString();
}
onLinkageListener.onPicked(fst.getName(), snd.getName(), thirdName);
}
}
}
/**
* 数据选择完成监听器
*/
public interface OnPickListener<Fst, Snd, Trd> {
void onPicked(Fst first, Snd second, Trd third);
}
/**
* 数据选择完成监听器
*/
public static abstract class OnStringPickListener implements OnPickListener<StringLinkageFirst, StringLinkageSecond, String> {
public abstract void onPicked(String first, String second, String third);
@Override
public void onPicked(StringLinkageFirst first, StringLinkageSecond second, String third) {
onPicked(first.getName(), second.getName(), third);
}
}
/**
* 兼容旧版API
*
* @deprecated use {@link OnStringPickListener} instead
*/
@Deprecated
public static abstract class OnLinkageListener extends OnStringPickListener {
}
/**
* 滑动过程数据联动监听器
*/
public interface OnWheelLinkageListener {
void onLinkage(int firstIndex, int secondIndex, int thirdIndex);
}
/**
* 兼容旧版API
*
* @deprecated use {@link OnWheelLinkageListener} instead
*/
@Deprecated
public static abstract class OnWheelListener {
public abstract void onFirstWheeled(int index, String item);
public abstract void onSecondWheeled(int index, String item);
public void onThirdWheeled(int index, String item) {
}
}
/**
* 数据提供接口
*/
public interface Provider<Fst extends LinkageFirst<Snd>, Snd extends LinkageSecond<Trd>, Trd> {
/**
* 是否只是二级联动
*/
boolean isOnlyTwo();
/**
* 初始化第一级数据
*/
@NonNull
List<Fst> initFirstData();
/**
* 根据第一级数据联动第二级数据
*/
@NonNull
List<Snd> linkageSecondData(int firstIndex);
/**
* 根据第一二级数据联动第三级数据
*/
@NonNull
List<Trd> linkageThirdData(int firstIndex, int secondIndex);
}
private static class StringLinkageFirst implements LinkageFirst<StringLinkageSecond> {
private String name;
private List<StringLinkageSecond> seconds = new ArrayList<>();
private StringLinkageFirst(String name, List<StringLinkageSecond> seconds) {
this.name = name;
this.seconds = seconds;
}
@Override
public String getName() {
return name;
}
@Override
public Object getId() {
return name;
}
@Override
public List<StringLinkageSecond> getSeconds() {
return seconds;
}
}
private static class StringLinkageSecond implements LinkageSecond<String> {
private String name;
private List<String> thirds = new ArrayList<>();
private StringLinkageSecond(String name, List<String> thirds) {
this.name = name;
this.thirds = thirds;
}
@Override
public String getName() {
return name;
}
@Override
public Object getId() {
return name;
}
@Override
public List<String> getThirds() {
return thirds;
}
}
/**
* 兼容旧版API
*/
public static abstract class DataProvider implements Provider<StringLinkageFirst, StringLinkageSecond, String> {
@NonNull
public abstract List<String> provideFirstData();
@NonNull
public abstract List<String> provideSecondData(int firstIndex);
@Nullable
public abstract List<String> provideThirdData(int firstIndex, int secondIndex);
@NonNull
@Override
public List<StringLinkageFirst> initFirstData() {
List<StringLinkageFirst> firsts = new ArrayList<>();
List<String> data = provideFirstData();
int i = 0;
for (String str : data) {
firsts.add(new StringLinkageFirst(str, linkageSecondData(i)));
i++;
}
return firsts;
}
@NonNull
@Override
public List<StringLinkageSecond> linkageSecondData(int firstIndex) {
List<StringLinkageSecond> seconds = new ArrayList<>();
List<String> data = provideSecondData(firstIndex);
int i = 0;
for (String str : data) {
seconds.add(new StringLinkageSecond(str, linkageThirdData(firstIndex, i)));
i++;
}
return seconds;
}
@NonNull
@Override
public List<String> linkageThirdData(int firstIndex, int secondIndex) {
List<String> thirdData = provideThirdData(firstIndex, secondIndex);
if (thirdData == null) {
thirdData = new ArrayList<>();
}
return thirdData;
}
}
/**
* 默认的数据提供者
*/
private static class DefaultDataProvider<Fst extends LinkageFirst<Snd>, Snd extends LinkageSecond<Trd>, Trd> implements Provider<Fst, Snd, Trd> {
private List<Fst> firstList = new ArrayList<>();
private List<List<Snd>> secondList = new ArrayList<>();
private List<List<List<Trd>>> thirdList = new ArrayList<>();
private boolean onlyTwo = false;
public DefaultDataProvider(List<Fst> f, List<List<Snd>> s, List<List<List<Trd>>> t) {
this.firstList = f;
this.secondList = s;
if (t == null || t.size() == 0) {
this.onlyTwo = true;
} else {
this.thirdList = t;
}
}
public boolean isOnlyTwo() {
return onlyTwo;
}
@Override
@NonNull
public List<Fst> initFirstData() {
return firstList;
}
@Override
@NonNull
public List<Snd> linkageSecondData(int firstIndex) {
return secondList.get(firstIndex);
}
@Override
@NonNull
public List<Trd> linkageThirdData(int firstIndex, int secondIndex) {
if (onlyTwo) {
return new ArrayList<>();
} else {
return thirdList.get(firstIndex).get(secondIndex);
}
}
}
}