CheckBox多选时间段,合并重复时间

      之前拿到了一个问题,在订购机票界面中需要一个时间筛选的功能,需求是让用户能够自由组合时间段,并且相邻时间段要合并,尽量少用if else 嵌套,可能问题看上去蛮简单,但对我这种没学过算法的还是要动一番脑子的,最终效果是这样


![O%[LSW~ZE6XTQ(BWAC2498.png

具体需求:

点击不不限的时候其他时间全部取消

两个相邻的时间勾上的时候中间相同的部分去掉,如00:00-14:00

四个时间全部选上的时候,时间的勾全部去掉,然后显示不限

    说下思路,这里面有5个CheckBox,既然是要根据它们的选中状态来组合改变数据,那怎么做?我想到了创建五个时间对象TimeTree,其中第一个和下面四个时间需要区分开来,所以加入一个int属性,名字就叫type,有0和1两个值。

    对于下面4个TimeTree,肯定需要有start和end两个String属性,分别对应起始时间和结束时间,如tt1的start是"0:00",end是"12:00"。

    另外每个对象中都应该持有对左右两个TimeTree对象的引用LeftTimeTree和RightTimeTree,这样方便接下来判断是否为相邻时间。当然一头一尾两个时间分别只有RightTimeTree和LeftTimeTree。

    其余部分都很简单,主要就是合并重复时间花了一番功夫,我的做法是用一个集合保存所有选中的TimeTree,只有下面4个会保存到集合中,点击'不限'会清空这个集合。

    在集合中有多个元素时,首先遍历集合,如果LeftTimeTree为空或者LeftTimeTree不包含在这个集合中,说明这是一个头时间点,记录下它的start,关键是求end,这里我写了一个递归方法,如果RightTimeTree包含在集合中,end就是RightTimeTree的end,再对RightTimeTree的end如此循环,就得到了最终应该显示的end。下面是代码


TimeTree类

public class TimeTree {
    public int type = 0;
    public String start;
    public String end;
    public String timeStr;
    public TimeTree leftTime;
    public TimeTree rightTime;
}

主界面

public class MainThreeAct extends Activity implements OnClickListener {
    List<String> timeNodes = Arrays.asList("0:00", "12:00", "14:00", "18:00", "24:00");
    private TextView tv;
    private LinearLayout ll;
    private CheckBox cb_012;
    private CheckBox cb_1214;
    private CheckBox cb_1418;
    private CheckBox cb_1824;
    private CheckBox cb_unlimit;
    // CheckBox集合
    private List<CheckBox> cbs;
    // 时间对象集合
    private List<TimeTree> times;
    // 选中的时间对象集合
    private List<TimeTree> selectedTimes = new ArrayList<TimeTree>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_three_activity);
        initVariables();
        initViews();
    }
    private void initVariables() {
        TimeTree tt0 = new TimeTree();
        TimeTree tt1 = new TimeTree();
        TimeTree tt2 = new TimeTree();
        TimeTree tt3 = new TimeTree();
        TimeTree tt4 = new TimeTree();
        times = Arrays.asList(tt0, tt1, tt2, tt3, tt4);
        for (int i = 1; i < times.size(); i++) {
            // type用来区分是不限(0),还是具体时间(1)
            times.get(i).type = 1;
            // 为每一个时间对象添加开始和结束时间
            times.get(i).start = timeNodes.get(i - 1);
            times.get(i).end = timeNodes.get(i);
            times.get(i).timeStr = timeNodes.get(i - 1) + "-" + times.get(i);
            // 为每一个时间对象添加相邻时间对象
            times.get(i).leftTime = i - 1 <= 0 ? null : times.get(i - 1);
            times.get(i).rightTime = i + 1 >= times.size() ? null : times.get(i + 1);
        }
    }
    private void initViews() {
        tv = (TextView) findViewById(R.id.tv);
        ll = (LinearLayout) findViewById(R.id.ll);
        cb_012 = (CheckBox) findViewById(R.id.cb012);
        cb_1214 = (CheckBox) findViewById(R.id.cb1214);
        cb_1418 = (CheckBox) findViewById(R.id.cb1418);
        cb_1824 = (CheckBox) findViewById(R.id.cb1824);
        cb_unlimit = (CheckBox) findViewById(R.id.cb_unlimit);
        cbs = Arrays.asList(cb_unlimit, cb_012, cb_1214, cb_1418, cb_1824);
        cb_012.setOnClickListener(this);
        cb_1214.setOnClickListener(this);
        cb_1418.setOnClickListener(this);
        cb_1824.setOnClickListener(this);
        cb_unlimit.setOnClickListener(this);
    }
    /**
     * CheckBox的点击监听
     */
    @Override
    public void onClick(View v) {
        CompoundButton buttonView = (CompoundButton) v;
        boolean isChecked = buttonView.isChecked();
        // 获取CheckBox的位置索引值
        int index = ll.indexOfChild(buttonView);
        // 根据位置索引,获取对应的时间对象
        TimeTree timeTree = times.get(index);
        // 取消CheckBox
        if (!isChecked) {
            if (index == 0) {
                return;
            }
            // 更新选中时间的集合
            selectedTimes.remove(timeTree);
            if (selectedTimes.size() == 0) {
                // 不限时间
                unlimitTime();
                return;
            }
            // 更新TextView
            setText();
            return;
        }
        // 选中CheckBox
        // 选中的是'不限'
        if (timeTree.type == 0) {
            unlimitTime();
            return;
        }
        // 选中了具体时间,首先将对应的时间对象记录下来
        selectedTimes.add(timeTree);
        // 全选中时不限时间
        if (selectedTimes.size() == times.size() - 1) {
            unlimitTime();
            return;
        }
        // 取消全选
        cbs.get(0).setChecked(false);
        // 更新TextView
        setText();
    }
    /**
     * 不限时间
     */
    private void unlimitTime() {
        selectedTimes.clear();
        for (int i = 1; i < cbs.size(); i++) {
            cbs.get(i).setChecked(false);
        }
        cbs.get(0).setChecked(true);
        tv.setText("不限");
    }
    /**
     * 根据选中的时间,来更新TextView
     */
    private void setText() {
        // 排序
        Collections.sort(selectedTimes, new Comparator<TimeTree>() {
            @Override
            public int compare(TimeTree lhs, TimeTree rhs) {
                return lhs.start.compareTo(rhs.start);
            }
        });
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < selectedTimes.size(); i++) {
            TimeTree timeTree = selectedTimes.get(i);
            if (timeTree.leftTime == null || !selectedTimes.contains(timeTree.leftTime)) {
                String start = timeTree.start;
                String end = timeTree.end;
                // 获取合并后的endTime
                end = updateEndTime(timeTree);
                sb.append(start + "-" + end + ",");
            }
        }
        String text = sb.toString();
        tv.setText(text.substring(0, text.length() - 1));
    }
    /**
     * 递归,获取合并后的endTime
     */
    private String updateEndTime(TimeTree timeTree) {
        String end = timeTree.end;
        if (timeTree.rightTime != null && selectedTimes.contains(timeTree.rightTime)) {
            end = updateEndTime(timeTree.rightTime);
        }
        return end;
    }
}