目录
一、测试环境说明
二、项目简介
该项目简介来自网络,具体内容需要自行测试
这款基于Android Studio开发的通讯录应用是一款功能完善、界面友好的联系人管理工具。应用采用现代化的设计理念,提供了完整的用户账号体系和数据管理功能。
1. 用户系统:支持账号注册、登录和密码修改,用户数据通过SharedPreferences安全存储。
2. 联系人管理:
- 支持添加、修改、删除联系人信息
- 联系人信息包括姓名、性别、多个电话号码、关系类型和备注等
- 提供详细的表单验证机制确保数据完整性
3. 搜索功能:
- 强大的联系人搜索功能
- 实时显示搜索结果数量
- 支持搜索结果的刷新和取消
4. 数据展示:
- 联系人列表视图
- 底部导航栏切换不同功能模块
- 个人中心显示统计信息
应用采用了Android开发的主流技术架构:
- 使用Fragment实现模块化界面
- 通过SQLite数据库持久化存储联系人数据
- 实现抽屉式导航界面
- 包含完善的表单验证和用户提示系统
- 采用响应式设计,适配不同屏幕尺寸
三、项目演示
网络资源模板--基于Android studio 通讯录App
四、部设计详情(部分)
登录页面
package com.example.myapplication;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.myapplication.databinding.ActivityMainBinding;
import com.example.myapplication.service.SharedPreferencesService;
import java.util.Map;
import java.util.Objects;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding mainBinding;
private Intent intent;
private boolean isRole = false; //登录的记录是否存在
/*--start--删除数据库--*/
// private static final String TAG = "MainActivity";
// private static final String DATABASE_NAME = "myLogInfo.db";
/*--end--*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(mainBinding.getRoot());
Map<String, String> userInfo = SharedPreferencesService.getUserInfo(this);
//自动填充已有账号
if (!userInfo.isEmpty() && !Objects.requireNonNull(userInfo.get("account")).isEmpty()) {
isRole = true;
mainBinding.dlZhh.setText(userInfo.get("account"));
mainBinding.dlMm.setText(userInfo.get("password"));
}
//登录按钮
mainBinding.dlAnn.setOnClickListener(view -> {
String roleName = mainBinding.dlZhh.getText().toString().trim();
String password = mainBinding.dlMm.getText().toString().trim();
if (!roleName.isEmpty() && !password.isEmpty()) {
if (isRole) {
if (userInfo.get("account").equals(roleName) && userInfo.get("password").equals(password)) {
intent = new Intent(this, MainActivity2PageView.class);
startActivity(intent);
finish();
// startActivityIfNeeded(intent, 1);
} else {
Toast.makeText(MainActivity.this, "账号或密码错误", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(MainActivity.this, "账号不存在", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(MainActivity.this, "账号或密码不能为空", Toast.LENGTH_SHORT).show();
}
}
}
采用MVC模式,将数据存取逻辑封装在SP中。登录验证时先检查账号是否存在,再核对密码,最后跳转到主页面。注释中还包含了删除数据库的备用代码段,方便调试时使用。整体实现了基本的用户认证流程。
1. 使用ViewBinding替代findViewById来绑定界面元素
2. 通过SharedPreferences存储和获取用户登录信息
3. 实现了自动填充已保存账号密码的功能
4. 包含登录验证逻辑,检查账号密码是否正确
5. 提供注册账号和修改密码的跳转功能
6. 使用Toast提示用户操作反馈
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/dl_bj"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/deng_lu"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/dl_tp"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="@drawable/tou_xiang"
app:layout_constraintBottom_toTopOf="@+id/guideline7"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintHorizontal_bias="0.462"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline4" />
<EditText
android:id="@+id/dl_zhh"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/text_1"
android:ems="10"
android:hint="请输入账号"
android:inputType="textPersonName"
app:layout_constraintBottom_toTopOf="@+id/dl_mm"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline7"
tools:ignore="TouchTargetSizeCheck" />
<EditText
android:id="@+id/dl_mm"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@drawable/text_1"
android:ems="10"
android:hint="请输入密码"
android:inputType="textPassword"
app:layout_constraintBottom_toTopOf="@+id/dl_ann"
app:layout_constraintEnd_toEndOf="@+id/dl_zhh"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/dl_zhh"
app:layout_constraintTop_toBottomOf="@+id/dl_zhh"
tools:ignore="TouchTargetSizeCheck" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.15" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.85" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.15" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.48" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.85" />
<Button
android:id="@+id/dl_ann"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@drawable/button_1"
android:text="登 录"
android:textAllCaps="false"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/dl_qhzhh"
app:layout_constraintEnd_toEndOf="@+id/dl_zhh"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/dl_zhh"
app:layout_constraintTop_toBottomOf="@+id/dl_mm" />
<LinearLayout
android:id="@+id/dl_qhzhh"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toEndOf="@+id/dl_zhh"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/dl_zhh"
app:layout_constraintTop_toBottomOf="@+id/dl_ann"
tools:ignore="MissingConstraints">
</LinearLayout>
<TextView
android:id="@+id/dl_myzhh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="没有账号?"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toStartOf="@+id/dl_wjmm"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline5" />
<TextView
android:id="@+id/dl_wjmm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="忘记密码?"
app:layout_constraintBottom_toBottomOf="@+id/dl_myzhh"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/dl_myzhh"
app:layout_constraintTop_toTopOf="@+id/dl_myzhh" />
</androidx.constraintlayout.widget.ConstraintLayout>
注册页面
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Environment;
import android.widget.Toast;
import com.example.myapplication.databinding.ActivityMainZhuCeBinding;
import com.example.myapplication.service.SharedPreferencesService;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
public class MainActivityZhuCe extends AppCompatActivity {
private ActivityMainZhuCeBinding mainZhuCeBinding;
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_zhu_ce);
mainZhuCeBinding = ActivityMainZhuCeBinding.inflate(getLayoutInflater());
setContentView(mainZhuCeBinding.getRoot());
//注册
mainZhuCeBinding.zhcAnn.setOnClickListener(view -> {
String roleName = mainZhuCeBinding.zhcZhh.getText().toString().trim();
String password = mainZhuCeBinding.zhcMm.getText().toString().trim();
String password2 = mainZhuCeBinding.zhcMm2.getText().toString().trim();
if (!(password.length()<6)) {
if (password.equals(password2)) {
boolean isSuccess = SharedPreferencesService.seveUserInfo(MainActivityZhuCe.this, roleName, password);
if (isSuccess) {
Toast.makeText(MainActivityZhuCe.this, "存储成功", Toast.LENGTH_SHORT).show();
intent = new Intent(this, MainActivity2PageView.class);
startActivity(intent);
} else {
Toast.makeText(MainActivityZhuCe.this, "存储失败", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(MainActivityZhuCe.this, "密码不一致", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(MainActivityZhuCe.this, "密码长度不少于6位", Toast.LENGTH_SHORT).show();
}
});
//已有账号
mainZhuCeBinding.zhcYyzhh.setOnClickListener(view -> {
intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
/*返回栈操作(未测试)*/
// // 移除返回栈顶部的Activity
// FragmentManager fragmentManager = getSupportFragmentManager();
// fragmentManager.popBackStack();
// // 移除特定ID的Activity
// int id = getResources().getIdentifier("my_activity", "id", getPackageName());
// fragmentManager.popBackStack(id, FragmentManager.POP_BACK_STACK_INCLUSIVE);
});
}
/*————————————————————start——————————————————
* 借鉴 https://blog.51cto.com/u_16175494/6870299 网址51CTO博客的代码
* 未使用
*/
/*private String generateCaptcha() {
// 生成随机的验证码
String captcha = generateRandomCaptcha();
// 将验证码图片保存到本地
saveCaptchaImage(captcha);
return captcha;
}
private String generateRandomCaptcha() {
// 随机生成4位验证码
Random random = new Random();
StringBuilder captcha = new StringBuilder();
for (int i = 0; i < 4; i++) {
captcha.append(random.nextInt(10));
}
return captcha.toString();
}
/*——————————————————end——————————————————*/
}
将用户数据存储逻辑封装在SharedPreferencesService中,实现了基本的用户注册流程验证。注释中还保留了验证码生成和图片保存的参考实现,方便后续功能扩展。整体实现了注册页面的核心功能需求。
1. 用户注册功能:
- 检查两次输入密码是否一致
- 验证密码长度是否达到6位以上
- 通过SharedPreferences存储用户注册信息
- 注册成功跳转到主页面
2. 界面交互:
- 使用ViewBinding绑定视图组件
- 提供"已有账号"按钮返回登录页
- 使用Toast提示用户操作结果
3. 其他特性:
- 包含验证码生成功能(注释状态)
- 尝试实现返回栈管理(注释状态)
通讯录首页
package com.example.myapplication;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import android.app.Fragment;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.TextView;
import android.widget.Toast;
import com.example.myapplication.Bean.ListAdapter;
import com.example.myapplication.Bean.RiJiInfoBean;
import com.example.myapplication.Dao.MySQLiteOpenHelper;
import com.example.myapplication.databinding.Activity2MainShouYeBinding;
import java.util.List;
import java.util.Objects;
public class MainActivityShouYe extends Fragment {
private Activity2MainShouYeBinding mainShouYeBinding;
private Intent intent;
private View view;
private List<RiJiInfoBean> riJiInfoBeanList;
private ListAdapter ListAdapter;
private MySQLiteOpenHelper mySQLiteOpenHelper;
private boolean isDrawerOpen; /*抽屉导航,开启为真*/
private boolean isQuery; /*查询标识,未查询为假*/
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mainShouYeBinding = Activity2MainShouYeBinding.inflate(inflater,container,false);
/*保持当前页面布局不被软键盘顶起*/
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
/*——————————————————————————start——————————————————————————————————*/
//这个registerForActivityResult方法要写在Activity的onCreate方法里(在Activity创建的时候就要创建出来,不能等到使用的时候再创建,不然会报错LifecycleOwner com.xx.MainActivity@28b4e79 is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.)。
/* ActivityResultLauncher<Intent> intentActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
//获取返回的结果
String data = result.getData().getStringExtra("test");
Toast.makeText(this, data, Toast.LENGTH_SHORT).show();
}
});
intent = new Intent();
intent.putExtra("test_name", "test_value");
intentActivityResultLauncher.launch(intent);*/
mySQLiteOpenHelper = new MySQLiteOpenHelper(getContext());
riJiInfoBeanList = mySQLiteOpenHelper.queryAllFromDB(0, null, null);
mainShouYeBinding = Activity2MainShouYeBinding.inflate(getLayoutInflater());
ListAdapter = new ListAdapter(riJiInfoBeanList, getContext());
mainShouYeBinding.shyList.setAdapter(ListAdapter);
mainShouYeBinding.shyTb.shyReSs.setVisibility(View.VISIBLE);
mainShouYeBinding.shyTb.shySs.setVisibility(View.VISIBLE);
/*列表滑动监听*/
mainShouYeBinding.shyList.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView absListView, int i) {
}
@Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
if (i > 1) {
mainShouYeBinding.shyFloatGd.setVisibility(View.VISIBLE);
} else {
mainShouYeBinding.shyFloatGd.setVisibility(View.GONE);
}
}
});
/*返回顶部*/
mainShouYeBinding.shyFloatGd.setOnClickListener(view -> {
/*滑动到顶层*/
mainShouYeBinding.shyList.smoothScrollToPosition(0);
});
/*列表点击事件*/
mainShouYeBinding.shyList.setOnItemClickListener((adapterView, view, i, l) -> {
RiJiInfoBean riJiInfoBean = riJiInfoBeanList.get(i);
if (getActivity() != null) {
intent = new Intent(getActivity(), MainActivity2BianXie.class);
intent.putExtra("name", riJiInfoBean.getName());
intent.putExtra("sex", riJiInfoBean.getSex());
intent.putExtra("phone", riJiInfoBean.getPhone());
intent.putExtra("phone2", riJiInfoBean.getPhone2());
intent.putExtra("relation", riJiInfoBean.getRelation());
intent.putExtra("reText", riJiInfoBean.getReText());
intent.putExtra("address", riJiInfoBean.getAddress());
/*修改标识*/
intent.putExtra("home", "update");
getActivity().startActivityIfNeeded(intent, 1);
}
});
/*列表长按事件*/
mainShouYeBinding.shyList.setOnItemLongClickListener((adapterView, view, i, l) -> {
RiJiInfoBean riJiInfoBean = riJiInfoBeanList.get(i);
LayoutInflater inflater2 = LayoutInflater.from(getActivity());
View customView = inflater2.inflate(R.layout.pop_up, null);
TextView title = customView .findViewById(R.id.up_bt);
TextView message = customView.findViewById(R.id.up_tsh);
title.setText("删除提示");
message.setText("是否删除 "+ riJiInfoBean.getName() +"的信息");
// 创建一个弹窗构造器
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(customView);
// 创建并显示弹窗
AlertDialog dialog = builder.create();
dialog.show();
/*弹窗-确认*/
TextView sure = customView.findViewById(R.id.up_qr);
sure.setOnClickListener(view1 -> {
boolean isSuccess = mySQLiteOpenHelper.deleteData(riJiInfoBean);
if (isSuccess){
Toast.makeText(getContext(), "删除成功", Toast.LENGTH_SHORT).show();
showQueryData();
}else {
Toast.makeText(getContext(), "删除失败", Toast.LENGTH_SHORT).show();
}
dialog.cancel();
});
/*弹窗-取消*/
TextView off = customView.findViewById(R.id.up_qx);
off.setOnClickListener(view1 -> {
dialog.cancel();
});
return true;
});
/*返回*/
mainShouYeBinding.shyTb.shyFh.setOnClickListener(view -> {
exitHint();
});
/*搜索 -- 打开抽屉*/
mainShouYeBinding.shyTb.shySs.setOnClickListener(view -> {
String name = mainShouYeBinding.chxSsk.getText().toString().trim();
if (name.isEmpty()) {
mainShouYeBinding.chxQx.setText("关 闭");
} else {
mainShouYeBinding.chxQx.setText("清 空");
}
mainShouYeBinding.shyZhy.openDrawer(Gravity.RIGHT);
});
/*抽屉监听事件*/
mainShouYeBinding.shyZhy.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
}
@Override
public void onDrawerOpened(@NonNull View drawerView) {
isDrawerOpen = true;
}
@Override
public void onDrawerClosed(@NonNull View drawerView) {
isDrawerOpen = false;
// 关闭系统键盘
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mainShouYeBinding.chxSsk.getWindowToken(), 0);
if (!isQuery) {
showQueryData();
mainShouYeBinding.shyTb.shyFh.setVisibility(View.VISIBLE);
mainShouYeBinding.shyTb.shyQk.setVisibility(View.GONE);
}
}
@Override
public void onDrawerStateChanged(int newState) {
}
});
/*搜索--查询*/
mainShouYeBinding.chxChx.setOnClickListener(view -> {
String name = mainShouYeBinding.chxSsk.getText().toString().trim();
if (!TextUtils.isEmpty(name)) {
long l = search(name);
mainShouYeBinding.chxTsh.setText("共搜索出" + l + "条数据");
if (l > 0) {
isQuery = true;
mainShouYeBinding.chxTsh.setTextColor(ContextCompat.getColor(getActivity(), R.color.yellow));
mainShouYeBinding.shyTb.shyFh.setVisibility(View.GONE);
mainShouYeBinding.shyTb.shyQk.setVisibility(View.VISIBLE);
mainShouYeBinding.shyZhy.closeDrawers();
mainShouYeBinding.chxSsk.clearFocus();
// 关闭系统键盘
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mainShouYeBinding.chxSsk.getWindowToken(), 0);
} else {
isQuery = false;
mainShouYeBinding.chxTsh.setTextColor(ContextCompat.getColor(getContext(), R.color.red));
}
mainShouYeBinding.shyList.setAdapter(new ListAdapter(riJiInfoBeanList, getContext()));
}
mainShouYeBinding.chxQx.setText("关 闭");
});
/*刷新搜索*/
mainShouYeBinding.shyTb.shyReSs.setOnClickListener(view -> {
if (isQuery) {
Toast.makeText(getContext(), "刷新成功,共" +
search(mainShouYeBinding.chxSsk.getText().toString().trim()) + "条数据", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getContext(), "刷新成功,共" +
showQueryData() + "条数据", Toast.LENGTH_SHORT).show();
}
});
/*取消搜索*/
mainShouYeBinding.shyTb.shyQk.setOnClickListener(view -> {
mainShouYeBinding.shyTb.shyFh.setVisibility(View.VISIBLE);
isQuery = false;
mainShouYeBinding.chxSsk.setText("");
mainShouYeBinding.chxTsh.setText("");
showQueryData();
mainShouYeBinding.shyTb.shyQk.setVisibility(View.GONE);
});
/*无字/有字有查-关闭,有字无查-清空*/
mainShouYeBinding.chxQx.setOnClickListener(view -> {
switch (mainShouYeBinding.chxQx.getText().toString().trim().substring(0, 1)) {
case "关":
if (!isQuery) {
riJiInfoBeanList = mySQLiteOpenHelper.queryAllFromDB(0, null, null);
mainShouYeBinding.shyList.setAdapter(new ListAdapter(riJiInfoBeanList, getContext()));
}
mainShouYeBinding.shyZhy.closeDrawer(GravityCompat.END);
break;
case "清":
mainShouYeBinding.chxSsk.setText("");
mainShouYeBinding.chxTsh.setText("");
isQuery = false;
mainShouYeBinding.chxQx.setText("关 闭");
break;
default:
}
});
/*搜索框监听事件*/
mainShouYeBinding.chxSsk.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (!mainShouYeBinding.chxSsk.getText().toString().trim().isEmpty()) {
int count = mySQLiteOpenHelper.queryCount(mainShouYeBinding.chxSsk.getText().toString().trim());
mainShouYeBinding.chxTsh.setTextColor(ContextCompat.getColor(getContext(), R.color.yellow));
if (count > 0) {
mainShouYeBinding.chxTsh.setText("已为您搜索出" + count + "条数据");
} else {
mainShouYeBinding.chxTsh.setText("未能查到数据");
}
mainShouYeBinding.chxQx.setText("清 空");
} else {
mainShouYeBinding.chxTsh.setText("");
mainShouYeBinding.chxQx.setText("关 闭");
}
}
});
return mainShouYeBinding.getRoot();
}
/*退出APP提示*/
protected void exitHint() {
LayoutInflater inflater = LayoutInflater.from(getContext());
View customView = inflater.inflate(R.layout.pop_up, null);
TextView title = customView.findViewById(R.id.up_bt);
TextView message = customView.findViewById(R.id.up_tsh);
title.setText("关闭通讯录提示");
message.setText("确认要退出通讯录吗?");
// 创建一个弹窗构造器
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(customView);
// 创建并显示弹窗
AlertDialog dialog = builder.create();
dialog.show();
/*弹窗-确认*/
TextView sure = customView.findViewById(R.id.up_qr);
sure.setOnClickListener(view1 -> {
getActivity().finish();
});
/*弹窗-取消*/
TextView off = customView.findViewById(R.id.up_qx);
off.setOnClickListener(view1 -> {
dialog.cancel();
});
}
/*搜索处理*/
@SuppressLint("SetTextI18n")
private long search(String name) {
riJiInfoBeanList = mySQLiteOpenHelper.queryAllFromDB(1, name, null);
return riJiInfoBeanList.size();
}
/*渲染列表*/
private long showQueryData() {
if (riJiInfoBeanList != null) {
riJiInfoBeanList.clear();
}
riJiInfoBeanList = mySQLiteOpenHelper.queryAllFromDB(0, null, null);
ListAdapter = new ListAdapter(riJiInfoBeanList, getContext());
mainShouYeBinding.shyList.setAdapter(ListAdapter);
return riJiInfoBeanList.size();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
/*public void Load() {
//title.setText("当前时间:\n" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}*/
/*在全局区域抽屉监听触摸事件*/
/*@Override
public boolean onTouchEvent(MotionEvent event) {
if (isDrawerOpen && drawerLayout.onTouchEvent(event)) {
isDrawerOpen = false;
}
return super.onTouchEvent(event);
}*/
}
1. 核心功能:
- 联系人列表展示与滑动浏览
- 联系人搜索功能(支持模糊查询)
- 联系人详情查看与编辑
- 联系人删除功能(带确认弹窗)
- 列表快速返回顶部功能
2. 交互设计:
- 使用DrawerLayout实现右侧抽屉式搜索面板
- 列表项点击进入编辑界面
- 列表项长按触发删除操作
- 智能搜索提示(实时显示匹配结果数)
- 退出应用确认对话框
3. 技术实现:
- 采用ViewBinding进行视图绑定
- 使用SQLite数据库存储联系人数据
- 自定义ListAdapter适配器渲染列表
- 监听软键盘和滚动事件优化用户体验
- 使用TextWatcher实现搜索框实时反馈
4. 其他特性:
- 保持布局不被软键盘顶起
- 列表滚动时显示返回顶部按钮
- 搜索状态标记与管理
- 提供数据刷新功能
五、项目源码
👇👇👇👇👇快捷方式👇👇👇👇👇