今天继续进行QQ界面的开发工作。前一段时间讲过ExpandableListView的使用并且设置了一个比较简单的具有子菜单效果的联系人列表,本节添加进ScrollView控件,对QQ2013版的联系人界面进行仿真。当然本质上是做一些美化工作,但是对于掌握Android界面的开发是很重要的,一个好看的界面对于手机应用至关重要。

  首先上图:

这是官方联系人效果图:

这是我自己做的效果图:

   

  官方版的最外面是一个TabView控件,本节先不考虑,可见和原版的效果还是比较相似的。(图标是我通过画图软件截过来的图,鉴于这只是交流学习,算不上侵权~)

  谈一下本节所涉及的一些知识点。

一、layer-list的使用方法

  layer-list的作用是叠放多个图层,这从名字上就可以看出,因为本节想做出一个一边没有边框,其它边界上没有边框的背景效果,使用<shape > 中的<stroke/>标签就没有办法满足了,解决的办法就是在drawable 文件夹中创建一个layer-list文件,然后创建两个图层<item>  第一个item放的是边框的颜色,第二个图层放的是内部的颜色,并且通过设置第二个item的根标签属性,设置第二个item比第一个item窄的程度,这样第一个item的颜色就会在边框处显示出来,从而做出边框的效果。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" ><item ><shape ><solid android:color="#cccccc"/></shape>   <!--上面是第一个图层--></item><item android:left="1dip" android:top="1dip" android:right="1dip" android:bottom="0dip">                       <!-- 上面一行是设置哪个边框的关键步骤,即第二个图层比第一个图层闪出来的边框! --><shape ><solid android:color="#f0f0f0"/></shape></item></layer-list>

  做这个有什么用呢?系列(十一)中两个Edittext重合的部分颜色很深,影响美观,因此可以通过创建layer-list文件,使得第一个EditText的下边框宽度为0,从而避免颜色加深的情况:

这里仅给出修改后的效果图:

二、如何理解ExpandableListView的生命周期?

  对于ExpandableListView,当刚刚创建该对象并且设置好适配器之后,EListView的每一个group都是没有展开的,当点击某一个group时,系统会把所有的group 和展开的childItem 重新绘制一遍,其中每一个的group 的最后一个childItem放的isLastChild 为true.

当有group展开或者关闭时会调用onGroupExpanded()和onGroupCollapsed() 方法。

三、如何动态获得ExpandableListView的高度?

创建一个一个int 变量 height,  在ExpandableListView刚刚创建时,设置其高度为所有group的宽度之和,然后当打开或者关闭group时,在onGroupExpanded()和onGroupCollapsed() 方法中对height 的值进行增加或者减少,并且通过LayoutParams对象即使更新空间的高度,从而实现动态更新ExpandableListView的高度。

具体代码如下:

  1、获得ListItem的高度,这里比如获得group的高度,需要调用适配器的getGroupView的方法

View listItem=  listView.getExpandableAdapter().getGroupView(参数);

listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));

//这一个必须有,因为listItem 在通过inflate()方法获得时并未指定父控件,因此导致onMeasure()方法中无法对宽度和高度进行解析,所以这里将布局类型强制设定成wrapContent 类型,然后再调用measure()方法

listItem.measure(0,0);

//0,0是两个参数,用于比较,measure()方法,用于计算控件的尺寸,关于该方法的具体细节请参考:http://blog.csdn.net/lilybaobei/article/details/8021868

int HEIGHT=listItem.getMeasuredHeight();

2、设置ExpandableListView的高度,通过LayoutParams对象

  ViewGroup.LayoutParams params=listView.getLayoutParams();

//获得尺寸参数

params.height=HEIGHT*3;

listView.setLayoutParams(params);

以上两点问题的提出主要是因把ListView、ExpandableListView放在一个 ScrollView中时往往会出现显示不全的问题,因此解决的办法就是动态更新ListView/ExListView的高度,以使列表能够显示完整。

四、ListView的边界比较模糊,颜色变淡,解决这个问题的方法是在ListView的属性设置中添加上  android:fadingEdge="none",这样边界就不会模糊了

基本上就是以上问题,下面上代码:

这是MainActivity的布局文件:

<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"android:background="#f1f1f1"tools:context=".MainActivity"android:scrollbars="vertical"android:scrollbarAlwaysDrawVerticalTrack="true" ><ScrollView android:id="@+id/qqlist_scroll"android:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayout android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><ListView android:id="@+id/qqlist_classify"android:layout_width="match_parent"android:layout_height="wrap_content"android:divider="#000000"android:dividerHeight="0px"android:fadingEdge="none"/><TextView android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/qqlist_classify_text"android:text="好友分组"android:textSize="6pt"android:textColor="#666666"android:padding="4dip"/><ExpandableListViewandroid:id="@+id/qq_list"android:layout_width="match_parent"android:layout_height="wrap_content"android:divider="#888888"android:dividerHeight="0px"android:fadingEdge="none"/><TextView android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/qqlist_classify_text"android:text="生活服务"android:textSize="6pt"android:textColor="#666666"android:padding="4dip"/><ListView android:id="@+id/qqlist_classify_down"android:layout_width="match_parent"android:layout_height="wrap_content"android:divider="#000000"android:dividerHeight="0px"/></LinearLayout></ScrollView></RelativeLayout>

然后就是第二个MainActivity.java  ,就是在系列(九)的基础上做了一定修改,添加了一个ListView的适配器和ExpandableListView的适配器:

因为控件数量比较多,所以代码比较多:

package com.dragon.android_qq;import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;import java.util.*;import com.dragon.persondata.ContactsInfo;public class ContactsListExpandable extends Activity {private int height=0;private  int GROUP_HEIGHT=0;private  int CHILD_HEIGHT=52;int[] photoRes={R.drawable.contact_0,R.drawable.contact_1,R.drawable.contact_2,R.drawable.contact_3};String[] groupFrom={"groupImage","groupName","childCount"};int[] groupTo={R.id.groupImage,R.id.groupName,R.id.childCount};String[] childFrom={"userImage","userName","userSign"};int[] childTo={R.id.ct_photo,R.id.ct_name,R.id.ct_sign};ArrayList<HashMap<String,Object>> groupData=null;ArrayList<ArrayList<HashMap<String,Object>>> childData=null; int[] groupIndicator={R.drawable.toright,R.drawable.todown};ExpandableListView exListView=null;ListView listViewTop=null,listViewDown=null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.layout_qqlist_expandable);groupData=new ArrayList<HashMap<String,Object>>();childData=new ArrayList<ArrayList<HashMap<String,Object>>> ();ContactsInfo user1=new ContactsInfo("暗夜之殇","总有一天会寻找到自己的幸福",R.drawable.contact_0,"我的好友");ContactsInfo user2=new ContactsInfo("街角的幸福","有些事终于想开了",R.drawable.contact_1,"我的好友");ContactsInfo user3=new ContactsInfo("愤怒的小胖","谁再叫我小胖我跟谁急!",R.drawable.contact_3,"朋友");ContactsInfo user4=new ContactsInfo("放羊的星星","What ever",R.drawable.contact_2,"陌生人");ContactsInfo user5=new ContactsInfo("都市丽人","我要我的完美",R.drawable.contact_4,"我的好友");addUser(user1);addUser(user2);addUser(user3);addUser(user4);addUser(user5);//不能用HashMap的实参赋给Map形参,只能new一个HashMap对象赋给Map的引用!
        exListView=(ExpandableListView)findViewById(R.id.qq_list);MyExpandableListViewAdapter adapter=new MyExpandableListViewAdapter(this,groupData,R.layout.layout_qqlist_group,groupFrom,groupTo,childData,R.layout.layout_qqlist_child,childFrom,childTo );exListView.setAdapter(adapter);exListView.setGroupIndicator(null);View exGroupListItem= exListView.getExpandableListAdapter().getGroupView(0,false, null, exListView );exGroupListItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));exGroupListItem.measure(0, 0);GROUP_HEIGHT=exGroupListItem.getMeasuredHeight();View exChildListItem=exListView.getExpandableListAdapter().getChildView(0, 0, false, null, exListView);exChildListItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));exChildListItem.measure(0, 0);CHILD_HEIGHT=exChildListItem.getMeasuredHeight();ViewGroup.LayoutParams  params= exListView.getLayoutParams();height=groupData.size()*GROUP_HEIGHT-2;params.height=height;exListView.setLayoutParams(params);listViewTop=(ListView)findViewById(R.id.qqlist_classify);ArrayList<HashMap<String,Object>> listTop=new ArrayList<HashMap<String,Object>>();HashMap<String,Object> mapTop1=new HashMap<String,Object>();HashMap<String,Object> mapTop2=new HashMap<String,Object>();HashMap<String,Object> mapTop3=new HashMap<String,Object>();mapTop1.put("listTopImage",R.drawable.address_list);mapTop1.put("listTopText", "通讯录");mapTop2.put("listTopImage",R.drawable.chat_flock);mapTop2.put("listTopText", "群");mapTop3.put("listTopImage",R.drawable.forum);mapTop3.put("listTopText", "讨论组");listTop.add(mapTop1);listTop.add(mapTop2);listTop.add(mapTop3);MyListViewAdapter adapterTop=new MyListViewAdapter(this, listTop,R.layout.qqlist_classify_item, new String[]{"listTopImage","listTopText"}, new int[]{R.id.qqlist_classify_image,R.id.qqlist_classify_name});listViewTop.setAdapter(adapterTop);ViewGroup.LayoutParams paramsTop=listViewTop.getLayoutParams();View listItem=listViewTop.getAdapter().getView(0, null, listViewTop);listItem.measure(0, 0);paramsTop.height=3*listItem.getMeasuredHeight()-2;//ListView属于一种ViewGroup类型
        listViewTop.setLayoutParams(paramsTop);/*** 创建一个String数组对象不能直接写String[]{}  必须在前面加上new,即写成 new String[]{"listTopImage","listTopText"}* */listViewDown=(ListView)findViewById(R.id.qqlist_classify_down);ArrayList<HashMap<String,Object>> listDown=new ArrayList<HashMap<String,Object>>();HashMap<String,Object> mapDown1=new HashMap<String,Object>();mapDown1.put("listTopImage",R.drawable.life_service);mapDown1.put("listTopText", "生活服务");listDown.add(mapDown1);listTop.add(mapTop3);MyListViewAdapter adapterDown=new MyListViewAdapter(this, listDown,R.layout.qqlist_classify_item, new String[]{"listTopImage","listTopText"}, new int[]{R.id.qqlist_classify_image,R.id.qqlist_classify_name});listViewDown.setAdapter(adapterDown);}protected void addUser(ContactsInfo user){int i;for(i=0; i< groupData.size(); i++){if(groupData.get(i).get("groupName").toString().equals(user.groupInfo)){break;}}if(i>=groupData.size()){HashMap<String,Object> map=new HashMap<String,Object>();map.put("groupImage", groupIndicator);map.put("groupName",user.groupInfo );map.put("childCount", 0);groupData.add(map);ArrayList<HashMap<String,Object>> list=new ArrayList<HashMap<String,Object>>();childData.add(list);}HashMap<String,Object> userData=new HashMap<String,Object>();userData.put("userImage",user.userImage );userData.put("userName", user.userName);userData.put("userSign", user.userSign);childData.get(i).add(userData);Integer count=(Integer)groupData.get(i).get("childCount")+1;groupData.get(i).put("childCount", count);    }/*** ExpandableListView对应的适配器* @author DragonGN**/public class MyExpandableListViewAdapter extends BaseExpandableListAdapter{private Context context=null;private ArrayList<HashMap<String,Object>> groupData=null;int groupLayout=0;private String[] groupFrom=null;private int[] groupTo=null;private ArrayList<ArrayList<HashMap<String,Object>>> childData=null;int childLayout=0;private String[] childFrom=null;private int[] childTo=null;public MyExpandableListViewAdapter(Context context, ArrayList<HashMap<String, Object>> groupData,int groupLayout, String[] groupFrom, int[] groupTo,ArrayList<ArrayList<HashMap<String, Object>>> childData, int childLayout,String[] childFrom, int[] childTo) {super();this.context = context;this.groupData = groupData;this.groupLayout = groupLayout;this.groupFrom = groupFrom;this.groupTo = groupTo;this.childData = childData;this.childLayout = childLayout;this.childFrom = childFrom;this.childTo = childTo;}@Overridepublic Object getChild(int arg0, int arg1) {// TODO Auto-generated method stubreturn null;}/*** position与id一样,都是从0开始计数的,* 这里返回的id也是从0开始计数的*/@Overridepublic long getChildId(int groupPosition, int childPosition) {// TODO Auto-generated method stublong id=0;for(int i=0;i<groupPosition; i++){id+=childData.size();}id+=childPosition;  return id;           }/**ChildViewHolder内部类**/class ChildViewHolder{ImageButton userImage=null;TextView userName=null;TextView userSign=null;}/**头像点击事件监听类**/class ImageClickListener implements OnClickListener{ChildViewHolder holder=null;public ImageClickListener(ChildViewHolder holder){this.holder=holder;}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubToast.makeText(context, holder.userName.getText()+" is clicked", Toast.LENGTH_SHORT).show();}}@Overridepublic View getChildView(int groupPosition, int childPosition,boolean isLastChild, View convertView, ViewGroup parent) {// TODO Auto-generated method stub/*** 这里isLastChild目前没用到,如果出现异常再说*/ChildViewHolder holder=null;if(convertView==null){convertView= LayoutInflater.from(context).inflate(childLayout,null);//感觉这里需要把root设置成ViewGroup 对象/*** ERROR!!这里不能把null换成parent,否则会出现异常退出,原因不太确定,可能是inflate方法获得的这个item的View* 并不属于某个控件组,所以使用默认值null即可*/holder=new ChildViewHolder();holder.userImage=(ImageButton)convertView.findViewById(childTo[0]);holder.userName=(TextView)convertView.findViewById(childTo[1]);holder.userSign=(TextView)convertView.findViewById(childTo[2]);convertView.setTag(holder);}else{holder=(ChildViewHolder)convertView.getTag();}holder.userImage.setBackgroundResource((Integer)(childData.get(groupPosition).get(childPosition).get(childFrom[0])));holder.userName.setText(childData.get(groupPosition).get(childPosition).get(childFrom[1]).toString());holder.userSign.setText(childData.get(groupPosition).get(childPosition).get(childFrom[2]).toString());holder.userImage.setOnClickListener(new ImageClickListener(holder));return convertView;}@Overridepublic int getChildrenCount(int groupPosition) {// TODO Auto-generated method stubreturn childData.get(groupPosition).size();}@Overridepublic Object getGroup(int groupPosition) {// TODO Auto-generated method stubreturn null;}@Overridepublic int getGroupCount() {// TODO Auto-generated method stubreturn groupData.size();}@Overridepublic long getGroupId(int groupPosition) {// TODO Auto-generated method stubreturn groupPosition;}class GroupViewHolder{ImageView image=null;TextView groupName=null;TextView childCount=null;}@Overridepublic View getGroupView(int groupPosition, boolean isExpanded,View convertView, ViewGroup parent) {// TODO Auto-generated method stubGroupViewHolder holder=null;if(convertView==null){convertView=LayoutInflater.from(context).inflate(groupLayout, null);holder=new GroupViewHolder();holder.image=(ImageView)convertView.findViewById(groupTo[0]);holder.groupName=(TextView)convertView.findViewById(groupTo[1]);holder.childCount=(TextView)convertView.findViewById(groupTo[2]);convertView.setTag(holder);}else{holder=(GroupViewHolder)convertView.getTag();} int[] groupIndicator=(int[])groupData.get(groupPosition).get(groupFrom[0]);holder.image.setBackgroundResource(groupIndicator[isExpanded?1:0]);holder.groupName.setText(groupData.get(groupPosition).get(groupFrom[1]).toString());holder.childCount.setText(groupData.get(groupPosition).get(groupFrom[2]).toString());if(groupPosition==groupData.size()-1){convertView.setBackgroundResource(R.drawable.list_lastitem_border);}else{convertView.setBackgroundResource(R.drawable.list_item_border);}//else的情况也要考虑,否则在绘制时出现错位现象return convertView;/*** 不要在适配器中调用适配器的内部方法,不然会出现奇怪的异常* */}@Overridepublic boolean hasStableIds() {// TODO Auto-generated method stubreturn false;}@Overridepublic boolean isChildSelectable(int groupPosition, int childPosition) {// TODO Auto-generated method stubreturn true;}/*** 在设置ExpandableListView的宽度的时候,要注意每次点击展开或者关闭时,各个Group和所要显示的Item都会重绘* 因此在每次绘制完毕之后都需要对height进行更新*/@Overridepublic void onGroupExpanded(int groupPosition) {// TODO Auto-generated method stubsuper.onGroupExpanded(groupPosition);System.out.println("已经展开了");height+=childData.get(groupPosition).size()*CHILD_HEIGHT;ViewGroup.LayoutParams  params= exListView.getLayoutParams();params.height=height-2;System.out.println("expand current height is "+height);exListView.setLayoutParams(params);}@Overridepublic void onGroupCollapsed(int groupPosition) {// TODO Auto-generated method stubsuper.onGroupCollapsed(groupPosition);height=height-childData.get(groupPosition).size()*CHILD_HEIGHT;ViewGroup.LayoutParams  params= exListView.getLayoutParams();System.out.println("collapse current height is "+height);params.height=height-2;exListView.setLayoutParams(params);}private int floatToInt(double f){if(f>0){return (int)(f+0.5);}else{return (int)(f-0.5);}}}/*** 这个是ListView的适配器* @author DragonGN**/public class MyListViewAdapter extends BaseAdapter{Context context=null;ArrayList<HashMap<String,Object>> list=null;int layout;String[] from=null;int[] to;public MyListViewAdapter(Context context,ArrayList<HashMap<String, Object>> list, int layout,String[] from, int[] to) {super();this.context = context;this.list = list;this.layout = layout;this.from = from;this.to = to;}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn list.size();}@Overridepublic Object getItem(int arg0) {// TODO Auto-generated method stubreturn null;}@Overridepublic long getItemId(int arg0) {// TODO Auto-generated method stubreturn arg0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubView listItemView= LayoutInflater.from(context).inflate(layout, null);ImageView image=(ImageView)listItemView.findViewById(to[0]);TextView text=(TextView)listItemView.findViewById(to[1]);image.setImageResource((Integer)list.get(position).get(from[0]));text.setText((String)list.get(position).get(from[1]));return listItemView;}}}

drawable文件中的图片和背景资源就不传了,若有需要,可以上传整个Demo。

另外还有一个效果没有实现,休息两天继续更新。

转载于:https://www.cnblogs.com/carlos-vic/p/Carlos_V_Android_12.html

Android开发系列(十二) QQ联系人列表升级版——ListView和ScrollView高阶使用方法...相关推荐

  1. BizTalk开发系列(十二) Schema设计之Group与Order

    更多内容请查看:BizTalk动手实验系列目录                       BizTalk 开发系列 开发BizTalk项目的时候会先约定各系统之间往来的消息格式. 由于BizTalk ...

  2. 【Qt编程】基于Qt的词典开发系列十二调用讲述人

    我们知道,win7系统自带有讲述人,即可以机器读出当前内容,具体可以将电脑锁定,然后点击左下角的按钮即可.之前在用Matlab写扫雷游戏的时候,也曾经调用过讲述人来进行游戏的语音提示.具体的Matla ...

  3. Android开发系列(二十八):使用SubMenu创建选项菜单

    大部分手机上边都会有一个"MENU"键,在一个应用安装到手机上之后,能够通过"MENU"显示该应用关联的菜单. 可是,从Android 3.0開始,Androi ...

  4. Android 10.0 SystemUI下拉状态栏UI定制化开发系列(十二)

    目录 1.概述 2.核心代码 3.核心代码部分分析 3.1 NotificationStackScrollLayout.java代码分析 3.2接下来分析Activat

  5. Android开发系列十:使用Jsoup解析HTML页面

    在写Android程序时,有时需要解析HTML页面,特别是那类通过爬网站抓取数据的应用,比如:天气预报等应用.如果是桌面应用可以使用htmlparser这个强大的工具,但是在Android平台上使用会 ...

  6. Android开发制作带有侧边栏的联系人列表

    首先需要下载pinyin4j-2.5.0.jar包,这是下载链接https://sourceforge.net/projects/pinyin4j/,下载完成之后在lib文件夹下面能够找到该jar包. ...

  7. android手机电话号码,Android开发:实现添加系统联系人(手机号码,姓名)

    之前遇到了一些知识没有总结的习惯,今天来回顾一下一个简单的小功能:Android开发中调起系统的联系人列表. 在网上收到了好多这方面的知识,自己在写代码的时候总结了一个最简化的方法,希望可以给大家提供 ...

  8. Android开发笔记(二十四)res目录的结构与配置

    res目录结构 res是Android项目工程中存放各类的目录,主要包括布局.图形与配置等等.res的子目录主要有: anim : 存放动画的描述文件 drawable : 存放各类图形的描述文件,包 ...

  9. Web 前端开发精华文章推荐(jQuery、HTML5、CSS3)【系列十二】

    2012年12月12日,[<Web 前端开发人员和设计师必读文章>系列十二]和大家见面了.梦想天空博客关注 前端开发 技术,分享各种增强网站用户体验的 jQuery 插件,展示前沿的 HT ...

最新文章

  1. 权重对生成对抗网络GAN性能的影响
  2. LeetCode第121题 买卖股票的最佳时机
  3. goland go test 多个文件_这个代码怎么会编译不通过?Goland 新手常见问题解决:GOPATH 和 Go Modules 编译不成功...
  4. BZOJ3527: [Zjoi2014]力
  5. PHP面试题:PHP加速模式/扩展? PHP调试模式/工具?
  6. connectionString加密
  7. Centos7默认自带了Python2.7版本,但是因为项目需要使用Python3.x,这里提供一种比较快捷方便的安装方式...
  8. 【我的物联网成长记12】当物联网遇上边缘计算
  9. 目标检测——域自适应只对同源的样本有效
  10. bat 自动输入密码_「docker实战篇」python的docker爬虫技术移动自动化uiautomator工具(16)...
  11. android恢复出厂设置的流程
  12. 边缘计算与嵌入式系统
  13. SpringBoot项目解决 log4j2 核弹漏洞
  14. Shell中的while用法
  15. SQL经典50查询语句案例_5(查询没学过“叶平”老师课的同学的学号、姓名)
  16. 苏州市软件行业协会第五届第四次理事会暨元宇宙专委会成立决议会在苏召开
  17. 服务器接显示器卡顿,外接屏幕会出现卡顿、掉帧等问题怎么解决?
  18. java中什么叫引用
  19. SIFT特征提取与检测
  20. CSS简单入门(一)

热门文章

  1. git ssh配置完后拉取代码_使用git在gitlab上拉取代码的方法
  2. 5天学会python_学会Python自动制作Word,将看到一个5天4位数的赚钱机会
  3. suse linux运行asp,Linux Supervisor的安装与使用入门---SuSE
  4. ionic4 QQ登陆集成
  5. 如何修改tomcat项目的图标
  6. android cocos2dx 3.15.1创建工程,Cocos2d-x创建android项目(cocos2d-x系列三)
  7. PHP更新小程序,微信小程序Tab页切换更新数据详细介绍
  8. linux账号和权限管理思维导图,Linux系统支持的思维导图软件有哪些?
  9. springboot完成进度条_Springboot从0开始第一周
  10. java顺序存储_顺序存储-数据结构-java实现