伴职创作「banzhi.cc」书客创作[ibooker.cc]Android开发经验谈

【Android】ExPandableListView实现时间轴

2017-09-03  本文已影响304人  吾非言

作者:邹峰立,微博:zrunker,邮箱:zrunker@yahoo.com,微信公众号:书客创作,个人平台:www.ibooker.cc

本文选自书客创作平台第39篇文章。阅读原文

书客创作

时间轴效果无论是移动端还是Web端,都是十分常见的功能之一,主要用来按照时间或相应的步骤来说明或展示相应的信息。在移动端实现时间轴效果的方式也非常多,那么今天就说说如何利用ExPandableListView来实现时间轴效果。

对于ExPandableListView基本使用方法,可以通过
【Android】ExpandableListView的使用这篇文章进行了解。

时间轴效果图

分析:从纵向来看整个时间轴被划分成左右两个部分,但是如果要使用ExPandableListView实现这样的效果,就无法通过左右两个部分进行分析了。因为ExPandableListView是二级列表。那么从横向来看,确实可以将其划分成二级列表的模式,例如可以将竖线之上的部分划分为一级列表,将竖线平行部分划分为二级列表,这样就可以将该时间轴按照ExPandableListView的思想来设计了。

一、首先是XML布局

1、在页面布局文件activity_timeline.xml中添加ExPandableListView控件。

<ExpandableListView
        android:id="@+id/expandlist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:cacheColorHint="#00000000"
        android:divider="@null"
        android:listSelector="@android:color/transparent"
        android:scrollbars="none" />

2、设置一级列表布局

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

    <TextView
        android:id="@+id/tv_step"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:gravity="end"
        android:text="@string/app_name"
        android:textColor="#555"
        android:textSize="16sp" />

    <ImageView
        android:id="@+id/img_dot"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_margin="10dp"
        android:layout_toEndOf="@id/tv_step"
        android:layout_toRightOf="@id/tv_step"
        android:contentDescription="@null"
        android:src="@drawable/guide_dot_choose" />

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toEndOf="@id/img_dot"
        android:layout_toRightOf="@id/img_dot"
        android:text="@string/app_name"
        android:textColor="@color/colorTitle"
        android:textSize="16sp" />
</RelativeLayout>
一级列表布局效果图

3、二级列表布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:gravity="center_vertical">

    <View
        android:id="@+id/view_line"
        android:layout_width="1dp"
        android:layout_height="match_parent"
        android:layout_marginLeft="95dp"
        android:layout_marginStart="95dp"
        android:background="#ccc" />

    <TextView
        android:id="@+id/tv_desc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="3dp"
        android:layout_marginEnd="10dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginStart="10dp"
        android:layout_marginTop="3dp"
        android:lineSpacingExtra="3dp"
        android:lines="1"
        android:text="@string/hello_world"
        android:textColor="#888" />

</LinearLayout>
二级列表布局效果图

二、设置列表数据对象

1、一级列表数据对象,一级列表数据对象类包含对应二级列表数据集。

public class TimeLineGroupData {
    private String gtitle;
    private String gstep;
    /**
     * 二级Item数据列表
     **/
    private List<TimeLineChildData> childList;

    public String getGtitle() {
        return gtitle;
    }
    public void setGtitle(String gtitle) {
        this.gtitle = gtitle;
    }
    public String getGstep() {
        return gstep;
    }
    public void setGstep(String gstep) {
        this.gstep = gstep;
    }
    public List<TimeLineChildData> getChildList() {
        return childList;
    }
    public void setChildList(List<TimeLineChildData> childList) {
        this.childList = childList;
    }
}

2、二级列表对象。

public class TimeLineChildData {
    /**
     * 描述信息
     **/
    private String desc;

    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
}

三、自定义Adapter

自定义ExPandableListView的适配器需要继承BaseExpandableListAdapter 。并实现一级列表和二级列表的相关处理方法。

public class TimeLineExpAdapter extends BaseExpandableListAdapter {
    private LayoutInflater inflater = null;
    private List<TimeLineGroupData> groupList = new ArrayList<>();

    /**
     * 构造方法
     */
    public TimeLineExpAdapter(Context context, List<TimeLineGroupData> group_list) {
        this.groupList = group_list;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    // 刷新数据
    public void flashData(List<TimeLineGroupData> datas) {
        this.groupList = datas;
        this.notifyDataSetChanged();
    }

    /**
     * 返回一级Item总数
     */
    @Override
    public int getGroupCount() {
        return groupList.size();
    }

    /**
     * 返回二级Item总数
     */
    @Override
    public int getChildrenCount(int groupPosition) {
        if (groupList.get(groupPosition).getChildList() == null) {
            return 0;
        } else {
            return groupList.get(groupPosition).getChildList().size();
        }
    }

    /**
     * 获取一级Item内容
     */
    @Override
    public Object getGroup(int groupPosition) {
        return groupList.get(groupPosition);
    }

    /**
     * 获取二级Item内容
     */
    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return groupList.get(groupPosition).getChildList().get(childPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    // 一级列表
    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        GroupViewHolder holder;
        if (convertView == null) {
            holder = new GroupViewHolder();
            convertView = inflater.inflate(R.layout.activity_timeline_group_item, parent, false);
            holder.stepTv = (TextView) convertView.findViewById(R.id.tv_step);
            holder.titleTv = (TextView) convertView.findViewById(R.id.tv_title);
            convertView.setTag(holder);
        } else {
            holder = (GroupViewHolder) convertView.getTag();
        }
        holder.titleTv.setText(groupList.get(groupPosition).getGstep());
        holder.stepTv.setText(groupList.get(groupPosition).getGtitle());
        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        ChildViewHolder viewHolder;
        TimeLineChildData entity = (TimeLineChildData) getChild(groupPosition, childPosition);
        if (convertView != null) {
            viewHolder = (ChildViewHolder) convertView.getTag();
        } else {
            viewHolder = new ChildViewHolder();
            convertView = inflater.inflate(R.layout.activity_timeline_child_item, parent, false);
            viewHolder.descTv = (TextView) convertView.findViewById(R.id.tv_desc);
            convertView.setTag(viewHolder);
        }
        viewHolder.descTv.setText(entity.getDesc());
        return convertView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return false;
    }

    private class GroupViewHolder {
        TextView titleTv, stepTv;
    }

    private class ChildViewHolder {
        TextView descTv;
    }
}

四、Activity实现

public class TimeLineActivity extends AppCompatActivity {
    private ExpandableListView expandlistView;
    private TimeLineExpAdapter statusAdapter;
    private List<TimeLineGroupData> groupList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timeline);

        initView();
        setListData();
        setAdapter();
        initExpandListView();
    }

    // 初始化控件
    private void initView() {
        expandlistView = (ExpandableListView) findViewById(R.id.expandlist);
    }

    /**
     * 自定义setAdapter
     */
    private void setAdapter() {
        if (statusAdapter == null) {
            statusAdapter = new TimeLineExpAdapter(this, groupList);
            expandlistView.setAdapter(statusAdapter);
        } else {
            statusAdapter.flashData(groupList);
        }
    }

    /**
     * 初始化可拓展列表
     */
    private void initExpandListView() {
        expandlistView.setGroupIndicator(null); // 去掉默认带的箭头
        expandlistView.setSelection(0);// 设置默认选中项

        // 遍历所有group,将所有项设置成默认展开
        int groupCount = expandlistView.getCount();
        for (int i = 0; i < groupCount; i++) {
            expandlistView.expandGroup(i);
        }

        expandlistView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                return true;
            }
        });
    }

    // 列表赋值
    private List<TimeLineGroupData> setListData() {
        if (groupList == null) {
            groupList = new ArrayList<>();
            // 一级列表数据
            for (int i = 0; i < 8; i++) {
                TimeLineGroupData timeLineGroupData = new TimeLineGroupData();
                timeLineGroupData.setGtitle("第" + i + "步");
                timeLineGroupData.setGstep("第" + i + "步的标题");
                // 二级列表数据
                ArrayList<TimeLineChildData> childDataList = new ArrayList<>();
                for (int j = 0; j < 2; j++) {
                    TimeLineChildData timeLineChildData = new TimeLineChildData();
                    timeLineChildData.setDesc("第" + i + "步描述" + j + "实现时间轴效果");
                    childDataList.add(timeLineChildData);
                }
                timeLineGroupData.setChildList(childDataList);
                groupList.add(timeLineGroupData);
            }
        }
        return groupList;
    }
}

到这里一个简单的时间轴效果就实现了,但是有几个地方需要注意:

注意1:要收到设置时间轴为展开状态。

 // 遍历所有group,将所有项设置成默认展开
int groupCount = expandlistView.getCount();
for (int i = 0; i < groupCount; i++) {
    expandlistView.expandGroup(i);
}

注意2:去掉默认带的箭头

expandlistView.setGroupIndicator(null);

Github地址
阅读原文


微信公众号:书客创作
上一篇 下一篇

猜你喜欢

热点阅读