Android自带的控件ExpandableListView实现了分组列表功能,本案例在此基础上进行优化,为此控件添加增删改分组及子项的功能,以及列表数据的持久化。

Demo实现效果:

GroupListDemo具体实现:

①demo中将列表页面设计为Fragment页面,方便后期调用;在主界面MainActivity中动态添加GroupListFragment页面;

MainActivity.java

package com.eric.grouplistdemo;

import android.app.Activity;

import android.app.Fragment;

import android.app.FragmentManager;

import android.os.Bundle;

import android.widget.RelativeLayout;

public class MainActivity extends Activity {

public static GroupListFragment fragment;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

fragment = new GroupListFragment();

getFragmentManager().beginTransaction()

.replace(R.id.fragContainer, fragment).commit();

}

}

动态添加GroupListFragment实例到界面的fragContainer布局中;将fragment声明为static用于在Adapter中组添加子项时进行调用。

activity_main.xml

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

android:id="@+id/fragContainer"

android:layout_width="match_parent"

android:layout_height="match_parent"

>

②实现自定义适配器类MyAdapter,继承自BaseExpandableListAdapter;组项布局及子项布局;

list_item_parent.xml组项布局文件,展开图标及名称,增删图标;

android:layout_width="match_parent"

android:layout_height="50dp"

android:background="#0099ff"

android:orientation="horizontal">

android:id="@+id/image_parent"

android:layout_width="50dp"

android:layout_height="50dp"

android:src="@drawable/image_parent1"/>

android:id="@+id/text_parent"

android:layout_width="wrap_content"

android:layout_height="50dp"

android:textColor="#FFF"

android:textSize="20sp"

android:text="parent1"

android:layout_toRightOf="@id/image_parent"

android:gravity="center"/>

android:id="@+id/image_delete"

android:layout_width="40dp"

android:layout_height="40dp"

android:layout_centerVertical="true"

android:layout_alignParentRight="true"

android:src="@drawable/delete"/>

android:id="@+id/image_add"

android:layout_width="40dp"

android:layout_height="40dp"

android:layout_centerVertical="true"

android:layout_toLeftOf="@id/image_delete"

android:src="@drawable/add"/>

list_item_child.xml子项布局文件,名称及删除图标;

android:layout_width="match_parent"

android:layout_height="40dp"

>

android:id="@+id/text_child"

android:layout_width="wrap_content"

android:layout_height="40dp"

android:layout_margin="5dp"

android:textColor="#0099ff"

android:text="child"

android:layout_centerInParent="true"

android:gravity="center"/>

android:id="@+id/image_delete"

android:layout_width="40dp"

android:layout_height="40dp"

android:layout_alignParentRight="true"

android:layout_centerVertical="true"

android:src="@drawable/delete"/>

MyAdapter.java自定义适配器

package com.eric.grouplistdemo;

import java.util.List;

import java.util.Map;

import android.content.Context;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.ViewGroup;

import android.widget.BaseExpandableListAdapter;

import android.widget.EditText;

import android.widget.ImageView;

import android.widget.TextView;

public class MyAdapter extends BaseExpandableListAdapter{

private List parentList;

private Map> map;

private Context context;

private EditText edit_modify;

private ModifyDialog dialog;

//构造函数

public MyAdapter(Context context, List parentList, Map> map) {

this.context = context;

this.parentList = parentList;

this.map = map;

}

//获取分组数

@Override

public int getGroupCount() {

return parentList.size();

}

//获取当前组的子项数

@Override

public int getChildrenCount(int groupPosition) {

String groupName = parentList.get(groupPosition);

int childCount = map.get(groupName).size();

return childCount;

}

//获取当前组对象

@Override

public Object getGroup(int groupPosition) {

String groupName = parentList.get(groupPosition);

return groupName;

}

//获取当前子项对象

@Override

public Object getChild(int groupPosition, int childPosition) {

String groupName = parentList.get(groupPosition);

String chidlName = map.get(groupName).get(childPosition);

return chidlName;

}

//获取组ID

@Override

public long getGroupId(int groupPosition) {

return groupPosition;

}

//获取子项ID

@Override

public long getChildId(int groupPosition, int childPosition) {

return childPosition;

}

@Override

public boolean hasStableIds() {

return true;

}

//组视图初始化

@Override

public View getGroupView(int groupPosition, boolean isExpanded,

View convertView, ViewGroup parent) {

final int groupPos = groupPosition;

if(convertView == null){

convertView = LayoutInflater.from(context).inflate(R.layout.list_item_parent, null);

}

ImageView image = (ImageView) convertView.findViewById(R.id.image_parent);

ImageView image_add = (ImageView) convertView.findViewById(R.id.image_add);

ImageView image_delete = (ImageView) convertView.findViewById(R.id.image_delete);

if(isExpanded){

image.setImageResource(R.drawable.image_parent2);

}else{

image.setImageResource(R.drawable.image_parent1);

}

image_add.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

alertAddDialog(MainActivity.fragment.getActivity(), "新增子项", groupPos);

}

});

image_delete.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

GroupListFragment.deleteGroup(groupPos);

}

});

TextView parentText = (TextView) convertView.findViewById(R.id.text_parent);

parentText.setText(parentList.get(groupPosition));

return convertView;

}

//子项视图初始化

@Override

public View getChildView(int groupPosition, int childPosition,

boolean isLastChild, View convertView, ViewGroup parent) {

final int groupPos = groupPosition;

final int childPos = childPosition;

if(convertView == null){

convertView = LayoutInflater.from(context).inflate(R.layout.list_item_child, null);

}

TextView childText = (TextView) convertView.findViewById(R.id.text_child);

ImageView image_delete = (ImageView) convertView.findViewById(R.id.image_delete);

String parentName = parentList.get(groupPosition);

String childName = map.get(parentName).get(childPosition);

childText.setText(childName);

image_delete.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

GroupListFragment.deleteChild(groupPos, childPos);

}

});

return convertView;

}

@Override

public boolean isChildSelectable(int groupPosition, int childPosition) {

return true;

}

//弹新增子项对话框

public void alertAddDialog(Context context, String title, int currentGroup){

final int group = currentGroup;

dialog = new ModifyDialog(context, title, null);

edit_modify = dialog.getEditText();

dialog.setOnClickCommitListener(new OnClickListener() {

@Override

public void onClick(View v) {

GroupListFragment.addChild(group, edit_modify.getText().toString());

dialog.dismiss();

}

});

dialog.show();

}

}

构造函数:将传入的parentList和map进行数据同步,parentList保存组数据,map保存对应组及其子项list数据;

获取分组数及子项数等很简单,就不介绍了,主要讲述一下,组视图初始化和子项视图初始化这两个函数;

组视图初始化getGroupView():尽量复用convertView防止内存泄露,首先是进行判断,若convertView为空,则进行组视图初始化,加载list_item_parent子项布局;获取到相应的组布局控件:展开图标image、添加图标image_add、删除图标image_delete;通过传递过来的布尔类型参数isExpanded,进行判断给image赋值展开图标或合并图标;分别给添加图标和删除图标添加点击事件,分别调用GroupListFragment中的弹出添加窗口函数alertAddDialog()和删除组函数deleteGroup();

子项视图初始化getChildView():同样尽量复用convertView防止内存泄露,首先是进行判断,若convertView为空,则进行子项视图初始化,加载list_item_child子项布局;获取到相应的子布局控件:内容文本ChildText和删除图标Image_delete;从parentList和map中分别获取到,当前子项的组名parentName和子项名childName,赋值ChildText,删除图标添加点击事件,调用删除子项函数deleteChild();

③实现自定义对话框类ModifyDialog,继承自Dialog类,对输入修改内容,或新增项内容进行过渡;

no_title_dialog.xml,在values目录下自定义Dialog的style类型xml,除去Dialog的标题栏;

300dp

40dp

true

dialog_modify.xml 自定义对话框的布局文件,标题文本,输入框,确定按钮;

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

android:id="@+id/text_title"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:gravity="center"

android:background="#0099ff"

android:text="修改名称"

android:textColor="#FFF"

android:textSize="20sp"/>

android:id="@+id/edit_modify"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="组名称"/>

android:id="@+id/btn_commit"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="确定"

android:textColor="#FFF"

android:background="#0099ff"

/>

ModifyDialog.java

package com.eric.grouplistdemo;

import android.app.Dialog;

import android.content.Context;

import android.view.LayoutInflater;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

public class ModifyDialog extends Dialog{

private TextView text_title;

private EditText edit_modify;

private Button btn_commit;

public ModifyDialog(Context context, String title, String name) {

super(context, R.style.noTitleDialog);

View view = LayoutInflater.from(getContext())

.inflate(R.layout.dialog_modify, null);

text_title = (TextView) view.findViewById(R.id.text_title);

edit_modify = (EditText)view.findViewById(R.id.edit_modify);

btn_commit = (Button) view.findViewById(R.id.btn_commit);

text_title.setText(title);

edit_modify.setText(name);

super.setContentView(view);

}

public EditText getEditText(){

return edit_modify;

}

public void setOnClickCommitListener(View.OnClickListener listener){

btn_commit.setOnClickListener(listener);

}

}

ModifyDialog自定义构造函数中,通过super()加载刚刚自定义的no_title_dialog.xml,声明View加载layout布局dialog_modify.xml;并且获取布局中的相应控件,将构造函数中传来的字符串title和name,分别赋值到标题文本和输入框控件中;最后调用setContentView()初始化对话框视图;

添加一个返回输入框控件的函数getEditText(),用于获取输入框输入的内容;

还需要一个自定义的点击事件监听器,绑定在确定按钮上;

④准备工作都完成了,下面就实现GroupListFragment,包括数据的初始化及持久化保存,组项和子项的增删改操作,列表子项点击事件,列表组项和子项的长按事件;

fragment_group_list.xml 页面的布局文件ExpandableListView列表以及一个添加组图标;

android:layout_width="match_parent"

android:layout_height="match_parent"

>

android:id="@+id/expandablelistview"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:groupIndicator="@null"

>

android:id="@+id/image_add"

android:layout_width="40dp"

android:layout_height="40dp"

android:layout_centerHorizontal="true"

android:layout_alignParentBottom="true"

android:src="@drawable/add"/>

这里需要将ExpandableListView的groupIndicator属性设置为@null,不使用其自带的展开图标;

GroupListFragment.java 加载列表的页面

package com.eric.grouplistdemo;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.json.JSONArray;

import org.json.JSONException;

import org.json.JSONObject;

import android.R.integer;

import android.app.Fragment;

import android.content.Context;

import android.content.SharedPreferences;

import android.content.SharedPreferences.Editor;

import android.os.Bundle;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.ViewGroup;

import android.widget.AdapterView;

import android.widget.EditText;

import android.widget.ExpandableListView;

import android.widget.ImageView;

import android.widget.Toast;

public class GroupListFragment extends Fragment{

private View view;

private ExpandableListView expandableListView;

public static MyAdapter adapter;

public static List parentList;

public static Map> map;

private ModifyDialog dialog;

private EditText edit_modify;

private ImageView image_add;

private int currentGroup,currentChild;

public static SharedPreferences sp;

public static Editor editor;

public static String dataMap,dataParentList;

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState) {

view = inflater.inflate(R.layout.fragment_group_list, container, false);

expandableListView = (ExpandableListView) view.findViewById(R.id.expandablelistview);

image_add = (ImageView) view.findViewById(R.id.image_add);

image_add.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

alertAddDialog(getActivity(), "新增组");

}

});

initData();

adapter = new MyAdapter(getActivity().getApplicationContext(), parentList, map);

expandableListView.setAdapter(adapter);

//设置子项点击事件

MyOnClickListener myListener = new MyOnClickListener();

expandableListView.setOnChildClickListener(myListener);

//设置长按点击事件

MyOnLongClickListener myLongListener = new MyOnLongClickListener();

expandableListView.setOnItemLongClickListener(myLongListener);

return view;

}

public void initData(){

map = new HashMap>();

parentList = new ArrayList();

sp = getActivity().getApplicationContext().getSharedPreferences("spfile", getActivity().MODE_PRIVATE);

dataMap = sp.getString("dataMap", null);

dataParentList = sp.getString("dataParentList", null);

if(dataMap == null || dataParentList == null){

parentList = new ArrayList();

parentList.add("客厅");

parentList.add("厨房");

parentList.add("卧室");

List list1 = new ArrayList();

list1.add("客厅空调");

list1.add("客厅电视");

list1.add("客厅电灯");

map.put("客厅", list1);

List list2 = new ArrayList();

list2.add("厨房油烟机");

list2.add("厨房电灯");

list2.add("厨房电器");

map.put("厨房", list2);

List list3 = new ArrayList();

list3.add("卧室空调");

list3.add("卧室灯光");

list3.add("卧室电视");

map.put("卧室", list3);

}else{

try {

//初始化parentList

JSONArray jsonArray = new JSONArray(dataParentList);

for (int i = 0; i < jsonArray.length(); i++) {

parentList.add(jsonArray.get(i).toString());

}

//初始化map

JSONObject jsonObject = new JSONObject(dataMap);

for (int i = 0; i < jsonObject.length(); i++) {

String key = jsonObject.getString(parentList.get(i));

JSONArray array = new JSONArray(key);

List list = new ArrayList();

for (int j = 0; j < array.length(); j++) {

list.add(array.get(j).toString());

}

map.put(parentList.get(i), list);

}

Log.d("eric", "①:"+map+"②:"+parentList);

} catch (JSONException e) {

e.printStackTrace();

Log.e("eric","String转Map或List出错"+e);

}

}

Log.e("eric", dataMap+"!&&!"+dataParentList);

saveData();

}

//自定义点击监听事件

public class MyOnClickListener implements ExpandableListView.OnChildClickListener{

@Override

public boolean onChildClick(ExpandableListView parent, View v,

int groupPosition, int childPosition, long id) {

String str = "choose"+groupPosition+"-"+childPosition;

Toast.makeText(getActivity(), str, Toast.LENGTH_SHORT).show();

return false;

}

}

//自定义长按监听事件

public class MyOnLongClickListener implements AdapterView.OnItemLongClickListener{

@Override

public boolean onItemLongClick(AdapterView> parent, View view,

int position, long id) {

//长按子项

if (ExpandableListView.getPackedPositionType(id) == ExpandableListView.PACKED_POSITION_TYPE_CHILD){

long packedPos = ((ExpandableListView) parent).getExpandableListPosition(position);

int groupPosition = ExpandableListView.getPackedPositionGroup(packedPos);

int childPosition = ExpandableListView.getPackedPositionChild(packedPos);

currentGroup = groupPosition;

currentChild = childPosition;

String str = (String)adapter.getChild(groupPosition, childPosition);

alertModifyDialog("修改此项名称",str);

Toast.makeText(getActivity(),str,Toast.LENGTH_SHORT).show();

return true;

//长按组

}else if(ExpandableListView.getPackedPositionType(id) == ExpandableListView.PACKED_POSITION_TYPE_GROUP){

long packedPos = ((ExpandableListView) parent).getExpandableListPosition(position);

int groupPosition = ExpandableListView.getPackedPositionGroup(packedPos);

int childPosition = ExpandableListView.getPackedPositionChild(packedPos);

currentGroup = groupPosition;

currentChild = childPosition;

String group = parentList.get(groupPosition);

alertModifyDialog("修改组名称", group);

String str = (String)adapter.getGroup(groupPosition);

Toast.makeText(getActivity(),str,Toast.LENGTH_SHORT).show();

}

return false;

}

}

//新增组

public static void addGroup(String newGroupName){

parentList.add(newGroupName);

List list = new ArrayList();

map.put(newGroupName, list);

adapter.notifyDataSetChanged();

saveData();

}

//新增子项到指定组

public static void addChild(int groupPosition, String newChildName){

String groupName = parentList.get(groupPosition);

List list = map.get(groupName);

list.add(newChildName);

adapter.notifyDataSetChanged();

saveData();

}

//删除指定组

public static void deleteGroup(int groupPos){

String groupName = parentList.get(groupPos);

map.remove(groupName);

parentList.remove(groupPos);

adapter.notifyDataSetChanged();

saveData();

}

//删除指定子项

public static void deleteChild(int groupPos, int childPos){

String groupName = parentList.get(groupPos);

List list = map.get(groupName);

list.remove(childPos);

adapter.notifyDataSetChanged();

saveData();

}

//修改该项名称

public void modifyName(int groupPosition, int childPosition, String modifyName){

Toast.makeText(getActivity(), String.valueOf(groupPosition)+'-'+String.valueOf(childPosition), Toast.LENGTH_SHORT).show();

if(childPosition<0){

//修改组名称

String groupName = parentList.get(groupPosition);

if(!groupName.equals(modifyName)){

map.put(modifyName, map.get(groupName));

map.remove(groupName);

parentList.set(groupPosition, modifyName);

}

}else{

//修改子项名称

String group = parentList.get(groupPosition);

List list =map.get(group);

list.set(childPosition, modifyName);

map.put(group, list);

}

adapter.notifyDataSetChanged();

saveData();

}

//弹修改对话框

public void alertModifyDialog(String title, String name){

dialog = new ModifyDialog(getActivity(), title, name);

edit_modify = dialog.getEditText();

dialog.setOnClickCommitListener(new OnClickListener() {

@Override

public void onClick(View v) {

modifyName(currentGroup, currentChild, edit_modify.getText().toString());

dialog.dismiss();

}

});

dialog.show();

}

//弹新增组对话框

public void alertAddDialog(Context context, String title){

dialog = new ModifyDialog(context, title, null);

edit_modify = dialog.getEditText();

dialog.setOnClickCommitListener(new OnClickListener() {

@Override

public void onClick(View v) {

addGroup(edit_modify.getText().toString());

dialog.dismiss();

}

});

dialog.show();

}

//保存数据

public static void saveData(){

JSONObject jsonObject = new JSONObject(map);

dataMap = jsonObject.toString();

dataParentList = parentList.toString();

editor = sp.edit();

editor.putString("dataMap", dataMap);

editor.putString("dataParentList", dataParentList);

editor.commit();

}

}

内容有点多,一个个来:

初始化Fragment页面函数onCreateView():

首先,要进行layout布局fragment_group_list.xml加载,获取相应控件的实例,expandableListView列表控件以及添加组图标image_add,添加组图标添加点击事件;调用initData()方法进行组数据parentList和组对应子项map的初始化;然后,实例化adapter传入parentList和map数据到自定义适配器MyAdapter中,并将其绑定到expandableListView上;最后,给expandableListView添加自定义子项点击事件监听器,组项和子项长按事件监听器;

初始化数据函数initData():该函数通过ShareReference来保存数据;

首先,实例化parentList和map,从ShareReference中获取到保存的String类型的parentList和map实际数据,赋值到dataMap和dataParentList中,若当中数据不存在,默认返回null,第一次运行程序的时候肯定是没有数据的,故进行判断,若没获取到数据,那就给parentList和Map赋值“客厅”、“厨房”、“卧室”等一系列数据;如果有数据的话,那就得进行数据的转换,因为之前保存的String类型数据,parentList初始化:将dataParentList转换为JSONArray类型,通过循环将数据赋值到parentList中;同理,将dataMap转换为JSONObject类型,通过两层for循环将数据赋值到map中。

自定义点击子项监听其类MyOnClickListener:实现ExpandableListView.OnChildClickListener接口,这里就简单的进行Toast操作,读者可以修改为跳转等其他自定义功能;

自定义长按组项或子项监听器类MyOnLongClickListener:实现AdapterView.OnItemLongClickListener接口,通过调用ExpandableListView的getPackedPositionType()方法来判断此时长按的是组项还是子项;这里将长按组和子项分离出来,方便根据功能修改;无论是组项还是子项长按后,都调用alertModifyDialog()弹修改对话框,传入当前项的名称;

新增组addGroup函数:将传递过来的newGroupName,添加parentList中,且定义一个空的list,绑定newGroupName,将这对string和list,添加到map中;最后,调用adapter.notifyDataSetChanged()刷新列表,调用saveData()保存数据到ShareReference;

同理,新增子项到指定组addChild(),删除指定组deleteGroup(),删除指定子项deleteChild(),都是对parentList和map进行操作,最后刷新列表和保存数据;

修改该项名称modifyName():通过传递过来childPosition进行判断,当修改项为组项时,childPosition的值为-1,以此区分组项和子项;这里遇到一个问题,当组项提交的名称与原名称相同会报错,故添加一个判断,仅提交的名称不同时才进行修改操作;修改的具体实现还是对parentList和map的操作,以修改组项为例,同新增组,添加一个modifyName的组,其对应的List为原来组名对应的List数据,然后再将原来的groupName组及其对应的list删除,实现修改;最后同样要刷新列表和保存数据;

弹修改对话框alertModifyDialog()函数:首先对自定义的dialog进行实例化,初始化标题和输入框中的数据;调用getEditText()函数获取输入框实例,添加提交按钮点击事件,调用modifyName方法传入当前组和子项数据,以及输入框中提交的文本;

弹新增组对话框alertAddDialog()函数:同样,实例化dialog,获取输入框控件,点击事件中调用addGroup()方法添加数据;

保存数据saveData()函数:将parentList和map数据转化为String类型,分别赋值,保存至ShareReference的Editor中并提交;

以上就是本文的全部内容,希望对大家的学习有所帮助。

java如何实现qq分组_Android仿QQ好友列表分组实现增删改及持久化相关推荐

  1. android 仿qq好友动态,Android UI仿QQ好友列表分组悬浮效果

    本文实例为大家分享了Android UI仿QQ好友列表分组悬浮效果的具体代码,供大家参考,具体内容如下 楼主是在平板上測试的.图片略微有点大,大家看看效果就好 接下来贴源代码: PinnedHeade ...

  2. java仿qq思路_java仿QQ聊天软件OIM艰辛之路(开源项目)

    既然QQ能仿ICQ, 咱java也来个仿QQ. 在我刚学完java后,就想做点什么项目锻炼下自己的技能.凑巧的是,我一个同样学java的朋友在做一个仿qq的项目,不过他做的实在太丑了. 然后他想让我也 ...

  3. 仿QQ好友列表分组折叠效果

    最近要一个类似QQ好友列表分组折叠效果,经过网友提醒应该使用ExpandableListView,因为其就集成了这个功能,我到网上随便找了文章一看,果然如此,因为工作需要和兴趣的推动,下班做完事后决定 ...

  4. 14_自定义ItemDecoration实现qq好友列表分组效果

    14_自定义ItemDecoration实现qq好友列表分组效果 一.先上效果 二.RecyclerView实现简单分组 RecyclerView比较常规的用法,显示多item布局,直接上代码: pu ...

  5. Android仿QQ ios dialog,仿QQ退出向上菜单

    Android仿QQ ios dialog,仿QQ退出向上菜单 EasyDialog两种模式 仿QQ退出向上菜单,自定义向上菜单              github地址:https://githu ...

  6. android的实现关注好友功能,android仿微信好友列表功能

    android studio实现微信好友列表功能,注意有一个jar包我没有放上来,请大家到MainActivity中的那个网址里面下载即可,然后把pinyin4j-2.5.0.jar复制粘贴到项目的a ...

  7. java从入门到精通二十四(三层架构完成增删改查)

    java从入门到精通二十四(三层架构完成增删改查) 前言 环境准备 创建web项目结构 导入依赖和配置文件 创建层次模型 实现查询 实现添加 实现修改 完成删除 做一个用户登录验证 会话技术 cook ...

  8. android 仿qq好友列表分组效果及联系人分组效果

     历史记录仿QQ好友列表的动态效果 以及联系人的分组效果 QQ朋友分组的功能做的不错,大家都很认可,那么到底他的分组并且滑动的时候,标题能停留在顶部是如何实现的呢?今天从网上搜索了一下资料,自己运行了 ...

  9. java通讯课程_Java项目实战-仿QQ即时通讯软件视频课程

    1.学习JAVA的Swing做UI设计, 2学习用JAVA语言进行数据库编程,熟练使用Connection,Statement,PreparedStatement,ResultSet等数据库类库: 3 ...

最新文章

  1. Sublime Text 3 快捷键精华版
  2. SAP UI5 how the ui library theme parameter is loaded
  3. 【bzoj4399】魔法少女LJJ 并查集+权值线段树合并
  4. 公共链接url出错_SEO优化技巧:关于URL的优化方法
  5. 华为云PB级数据库GaussDB(for Redis)介绍第四期:高斯 Geo的介绍与应用
  6. C语言CURL实现HTTP POST、GET、PUT
  7. C#开发命令执行驱动程序 之 控制标志的命令行参数
  8. 每天早上喝一杯豆浆不吃饭,一个月后会是什么反应?
  9. JDBC、JDBC连接池、JDBCTemplate
  10. 《Nmap渗透测试指南》—第2章2.8节ICMP Ping Types扫描
  11. Enterprise Library 5.0 中的Validators
  12. redis实现队列的几种方式(LPUSH/BRPOP,发布/订阅模式,stream)
  13. 教育系统APP(四)
  14. 调试经验——使用Matlab绘制f(x)=sin(x)/x的函数图形
  15. DotNetCasClient 如何获取Cas服务器返回的attributes中的数据
  16. 《Security of GPS/INS based On-road Location Tracking Systems》论文翻译
  17. 带刺玫瑰特别美?OLED屏幕画面美但眼睛会累
  18. 前端资源压缩合并maven插件之wro4j
  19. form提交前进行确认提示
  20. mysql串口转网口,串口转网口的传输程序SerialServer

热门文章

  1. oracle数据库or exists,Oracle Not Exists运算符
  2. 网站域名注册信息怎么查询?
  3. 判断当前终端是移动端还是PC端
  4. 一图看懂,阿里云飞天企业版如何支持政企数智创新
  5. linux怎么查找文件名带有abc的文件,如何查找一个文件夹里的最新的文件
  6. C++:shared_ptr简介以及常见问题
  7. 从业18年,我总结了9个最有价值的经验 9 Hard Lessons I Learned During My 18 Years
  8. Zookeeper介绍(通俗易懂)
  9. 2009年A股各板块龙头股大全(转载)
  10. ArcPy计算多影像有效像元的平均值