Android(安卓)模仿QQ登录下拉历史列表
前言
各位同学大家好,很长一段时间没有给大家更新文章,因为本人从事安卓开发的工作(游戏SDK)。今天就总结一个小知识点分享给大家 Android仿QQ登录下拉历史列表 ,网上也有很多很好用的例子,我这边也只是做个笔记顺带分享给大家。如果有错误或者纰漏的地方 希望大家能指正,废话不多说我们这是正式开始。
##准备工作
1装好安卓开发环境jdk Android studio 或者eclipse +adt 都可以 这个同学们自己去安装吧,我就不展开讲了
效果图
我们的需求和明确,就是要把登录成功的账号密码缓存保存好,然后并且显示到历史信息列表里面让用户可以自由切换已经登录过的账号。
具体实现
我这边是写了一个数据模型bean类 selectphone;
package com.example.accountrecord/*** * 用户登录信息 * */public class SelectPhone { private String account_id; private String name; private String password; private String user_type; private String token; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } public String getUser_type() { return user_type; } public void setUser_type(String user_type) { this.user_type = user_type; } public String getPassword() { return password; } public void setPassword(String password) this.password = password; } public String getAccount_id() { return account_id; } public void setAccount_id(String account_id) { this.account_id = account_id; }}
然后在将多条selectphone 存储在list集合里面 使用的存储方案是安卓自带的 SharedPreferences
但是SharedPreferences 默认只支持基础数据类型 所以我们要做简单的转换改造 将list转成json字符串存起来 获取的适合我们再讲json还原成list集合
存储
/** * 4.存储账本SelectPhone的list */ public static void putSelectBean(Context context, List phoneList, String key) { if (sp == null) { sp = context.getSharedPreferences("config", MODE_PRIVATE); } SharedPreferences.Editor editor = sp.edit(); Gson gson = new Gson(); String json = gson.toJson(phoneList); editor.putString(key, json); editor.commit(); }
读取
/** * 读取账本SelectPhone的list */ public static List getSelectBean(Context context, String key) { if (sp == null) { sp = context.getSharedPreferences("config", MODE_PRIVATE); } Gson gson = new Gson(); String json = sp.getString(key, null); Type type = new TypeToken>() { }.getType(); List arrayList = gson.fromJson(json, type); return arrayList; }
loginActivity 中具体调用存储数据
private void login(){ account=account_ed.getText().toString(); password=password_ed.getText().toString(); if(TextUtils.isEmpty(account)||TextUtils.isEmpty(password)){ Toast.makeText(mContext,"账号或者密码输入不能为空",Toast.LENGTH_LONG).show(); } SelectPhone selectPhone=new SelectPhone(); selectPhone.setName(account); selectPhone.setPassword(password); List getdata = SharedPreferencesUtils.getSelectBean(LoginActivity.this, "selectphone"); if (getdata != null && getdata.size() > 0) { getdata.add(0,selectPhone); SharedPreferencesUtils.putSelectBean(LoginActivity.this, getdata, "selectphone"); } else { data.add(selectPhone); SharedPreferencesUtils.putSelectBean(LoginActivity.this, data, "selectphone"); } Toast.makeText(mContext,"登录成功数据缓存成功",Toast.LENGTH_LONG).show(); finish(); }
弹出的popupwindow 具体实现:
布局代码:
<?xml version="1.0" encoding="utf-8"?>
具体逻辑代码:
package com.example.accountrecord;import java.util.List;import android.content.Context;import android.graphics.drawable.ColorDrawable;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.AdapterView.OnItemClickListener;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.ListView;import android.widget.PopupWindow;import android.widget.RelativeLayout;import android.widget.TextView/** * 自定义PopupWindow 主要用来显示ListView * * @param * @param * @create time */public class SpinerPopWindow extends PopupWindow { private static final String TAG = "SpinerPopWindow"; private LayoutInflater inflater; private ListView mListView; private List list; private MyAdapter mAdapter; private Context context; private RemoveUserinfoListner removeUserinfoListner; public SpinerPopWindow(Context context, List list, OnItemClickListener clickListener, RemoveUserinfoListner removeUserinfoListner) { super(context); inflater = LayoutInflater.from(context); this.list = list; this.context = context; this.removeUserinfoListner = removeUserinfoListner; init(clickListener); } private void init(OnItemClickListener clickListener) { //View view = inflater.inflate(R.layout.select_phonedialog, null); View view = inflater.inflate(ResourceUtil.getLayoutId(context, "select_phonedialog"), null); setContentView(view); setFocusable(true); setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); ColorDrawable dw = new ColorDrawable(0x00); setBackgroundDrawable(dw); //mListView = view.findViewById(R.id.select_listview); mListView = view.findViewById(ResourceUtil.getId(context, "select_listview")); mAdapter = new MyAdapter(); if (list != null) { mListView.setAdapter(mAdapter); } mListView.setOnItemClickListener(clickListener); } private class MyAdapter extends BaseAdapter { @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { final SelectPhone selectPhone = (SelectPhone) list.get(position); ViewHodler hodler = null; if (convertView == null) { convertView = LayoutInflater.from(context).inflate(ResourceUtil.getLayoutId(context, "selectphone_item"), parent, false); hodler = new ViewHodler(); hodler.phonetextview = convertView.findViewById(ResourceUtil.getId(context, "account_textview"));//account_textview //account_image hodler.imageview = convertView.findViewById(ResourceUtil.getId(context, "account_image")); hodler.deleterl = convertView.findViewById(ResourceUtil.getId(context, "delete_account_rl")); convertView.setTag(hodler); } else { hodler = (ViewHodler) convertView.getTag(); } hodler.phonetextview.setText(selectPhone.getName()); //操作删除存在对象里面的数据刷新listview hodler.deleterl.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // data.remove(position); DeleteaccountDialog deleteaccountDialog = new DeleteaccountDialog(context, selectPhone.getName(), new Deleteaccountlistener() { @Override public void deleteaccountsuccess() { notifyDataSetChanged(); removeUserinfoListner.removeuserinfosuccess(position, (List) list); } }); deleteaccountDialog.show(); } }); return convertView; } public class ViewHodler { TextView phonetextview; ImageView imageview; RelativeLayout deleterl; } }}
删除弹窗dialog的实现:
布局文件
<?xml version="1.0" encoding="utf-8"?>
逻辑代码:
package com.example.accountrecord;import android.app.Dialog;import android.content.Context;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.Window;import android.widget.RelativeLayout;import android.widget.TextView;/** * 类说明:删除账号是否确认弹窗 * 创建人:xuqing * 创建时间:2019-04-29 */public class DeleteaccountDialog extends Dialog { private Context context; private RelativeLayout cancel, confirm; private TextView accounttext; private Deleteaccountlistener deleteaccountlistener; private String account; public DeleteaccountDialog(Context context, String account, Deleteaccountlistener deleteaccountlistener) { super(context); this.context = context; this.account = account; this.deleteaccountlistener = deleteaccountlistener; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setBackgroundDrawableResource(android.R.color.transparent); getWindow().requestFeature(Window.FEATURE_NO_TITLE); LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(ResourceUtil.getLayoutId(context, "deleteaccount_dialog"), null); setContentView(layout); initview(); } private void initview() { cancel = findViewById(ResourceUtil.getId(context, "deleteaccount_cancel")); confirm = findViewById(ResourceUtil.getId(context, "deleteaccount_confirm")); accounttext = findViewById(ResourceUtil.getId(context, "deleteaccount_text")); accounttext.setText("确定删除账号[" + account + "]"); //删除账号取消 cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { DeleteaccountDialog.this.dismiss(); } }); //确定删除账号 confirm.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { DeleteaccountDialog.this.dismiss(); deleteaccountlistener.deleteaccountsuccess(); } }); }}
我们在loginactivity中调用自定义的popupwindow 显示列表的时候我们要注意几个回调
首先看具体调用
getdata = SharedPreferencesUtils.getSelectBean(mContext, "selectphone"); if (getdata != null && getdata.size() > 0) { SelectPhone phone = getdata.get(0); cacheaccount = phone.getName(); cachepsw=phone.getPassword(); if (!TextUtils.isEmpty(cacheaccount)) { account_ed.setText(cacheaccount); password_ed.setText(cachepsw); } else { account_ed.setText(null); password_ed.setText(null); } } mSpinerPopWindow = new SpinerPopWindow(LoginActivity.this, getdata, itemClickListener, removeUserinfoListner); mSpinerPopWindow.setOnDismissListener(dismissListener);
用户点击列表里面的某一条信息的回调监听
/** * popupwindow显示的ListView的item点击事件 */ private AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { mSpinerPopWindow.dismiss(); flag = false; SelectPhone selectPhone = getdata.get(position); String getusername = selectPhone.getName(); String psw = selectPhone.getPassword(); account_ed.setText(getusername); password_ed.setText(psw); } };
用户点击空白部分的监听:
/** * 监听popupwindow取消 */ private PopupWindow.OnDismissListener dismissListener = new PopupWindow.OnDismissListener(){ @Override public void onDismiss() { flag = false; } };
用户点击确认删除按钮的监听:
//删除用户缓存信息 private RemoveUserinfoListner removeUserinfoListner = new RemoveUserinfoListner() { @Override public void removeuserinfosuccess(int position, List data) { if (data != null && data.size() > 0) { data.remove(position); SharedPreferencesUtils.putSelectBean(mContext, data, "selectphone"); flag = false; List getdata = SharedPreferencesUtils. getSelectBean(LoginActivity.this, "selectphone"); if (getdata != null && getdata.size() > 0) { SelectPhone selectPhone = getdata.get(0); account_ed.setText(selectPhone.getName()); password_ed.setText(selectPhone.getPassword()); } else { account_ed.setText(null); password_ed.setText(null); } } else { Toast.makeText(mContext,"缓存数据为空",Toast.LENGTH_LONG).show(); } } };
我们需要在相应的用户操作的监听回调里面去更新一些UI来满足我们的需求
最后完整的loginactivity 的布局代码和 java逻辑代码也贴上
loginactivity xml文件 :
<?xml version="1.0" encoding="utf-8"?>
loginactivity 完整java代码
package com.example.accountrecord;import androidx.appcompat.app.AppCompatActivity;import android.content.Context;import android.os.Bundle;import android.text.TextUtils;import android.view.View;import android.widget.AdapterView;import android.widget.Button;import android.widget.EditText;import android.widget.PopupWindow;import android.widget.RelativeLayout;import android.widget.TextView;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class LoginActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "LoginActivity"; private EditText account_ed ,password_ed; private String account, password; private Boolean flag=false; private Button loginbtn; List getdata=null; private Context mContext=LoginActivity.this; private TextView textView; private RelativeLayout select_loginaccount_rl; private String cacheaccount ,cachepsw; private SpinerPopWindow mSpinerPopWindow; List data=new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); initview(); } private void initview() { account_ed=findViewById(R.id.login_account_ed); password_ed=findViewById(R.id.account_login_psw); loginbtn=findViewById(R.id.promptly_login); loginbtn.setOnClickListener(this); textView=findViewById(R.id.login_account_textview); select_loginaccount_rl=findViewById(R.id.select_loginaccount_rl); select_loginaccount_rl.setOnClickListener(this); getdata = SharedPreferencesUtils.getSelectBean(mContext, "selectphone"); if (getdata != null && getdata.size() > 0) { SelectPhone phone = getdata.get(0); cacheaccount = phone.getName(); cachepsw=phone.getPassword(); if (!TextUtils.isEmpty(cacheaccount)) { account_ed.setText(cacheaccount); password_ed.setText(cachepsw); } else { account_ed.setText(null); password_ed.setText(null); } } mSpinerPopWindow = new SpinerPopWindow(LoginActivity.this, getdata, itemClickListener, removeUserinfoListner); mSpinerPopWindow.setOnDismissListener(dismissListener); } //删除用户缓存信息 private RemoveUserinfoListner removeUserinfoListner = new RemoveUserinfoListner() { @Override public void removeuserinfosuccess(int position, List data) { if (data != null && data.size() > 0) { data.remove(position); SharedPreferencesUtils.putSelectBean(mContext, data, "selectphone"); flag = false; List getdata = SharedPreferencesUtils. getSelectBean(LoginActivity.this, "selectphone"); if (getdata != null && getdata.size() > 0) { SelectPhone selectPhone = getdata.get(0); account_ed.setText(selectPhone.getName()); password_ed.setText(selectPhone.getPassword()); } else { account_ed.setText(null); password_ed.setText(null); } } else { Toast.makeText(mContext,"缓存数据为空",Toast.LENGTH_LONG).show(); } } }; /** * 监听popupwindow取消 */ private PopupWindow.OnDismissListener dismissListener = new PopupWindow.OnDismissListener() { @Override public void onDismiss() { flag = false; } }; /** * popupwindow显示的ListView的item点击事件 */ private AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { mSpinerPopWindow.dismiss(); flag = false; SelectPhone selectPhone = getdata.get(position); String getusername = selectPhone.getName(); String psw = selectPhone.getPassword(); account_ed.setText(getusername); password_ed.setText(psw); } }; @Override public void onClick(View view) { switch (view.getId()){ case R.id.promptly_login: login(); break; case R.id.select_loginaccount_rl: if (flag) { flag = false; if (mSpinerPopWindow != null) { mSpinerPopWindow.dismiss(); } } else { flag = true; if (mSpinerPopWindow != null) { mSpinerPopWindow.showAsDropDown(textView); } } break; default: break; } } private void login(){ account=account_ed.getText().toString(); password=password_ed.getText().toString(); if(TextUtils.isEmpty(account)||TextUtils.isEmpty(password)){ Toast.makeText(mContext,"账号或者密码输入不能为空",Toast.LENGTH_LONG).show(); } SelectPhone selectPhone=new SelectPhone(); selectPhone.setName(account); selectPhone.setPassword(password); List getdata = SharedPreferencesUtils.getSelectBean(LoginActivity.this, "selectphone"); if (getdata != null && getdata.size() > 0) { getdata.add(0,selectPhone); SharedPreferencesUtils.putSelectBean(LoginActivity.this, getdata, "selectphone"); } else { data.add(selectPhone); SharedPreferencesUtils.putSelectBean(LoginActivity.this, data, "selectphone"); } Toast.makeText(mContext,"登录成功数据缓存成功",Toast.LENGTH_LONG).show(); finish(); }}
到此整个仿QQ的登录下拉历史功能实现基本讲完了 主要关键点是数据存储的逻辑要注意, UI实现相对简单。
最后总结:
我是一名Android 游戏SDK开发的人程序员 ,因为最近用到这个仿QQ下拉历史列表的功能(之前很在就实现过)所以就用户原生的api写一个 当做笔记分享给大家。 希望能帮助到各位同学,同事我学习的技术栈还有 java web flutter 跨平台等 ,如果觉得文章还不错麻烦给个star 谢谢有兴趣的同学可以加我个人微信/QQ(1693891473)
项目地址: https://github.com/xq19930522/accountrecord_demo
QQ交流群:
更多相关文章
- (转)关于android的4.2的0文件夹的详解(目录结构挂载分析)
- Android的apk安装时签名相同冲突解决
- Android开发基础之AlertDialog的单选对话框的使用
- Android之实现定时开关机
- Toast(吐司提示)的曾经、现在与未来
- android获取web服务器端session并验证登陆 一
- Android中Fragment嵌套生命周期响应问题
- 腾讯微博java(android) sdk 帐户相关api详细介绍
- android轻量级开源缓存框架——ASimpleCache(ACache)源码分析(封装