在平常使用手机的进程中,我们常常希望有这样1个功能:可以对我们的某1个利用加锁,进入的时候需要输入密码验证身份,然后才可以进入主界面,这就是1个程序锁的功能。其实这类功能其实不难实现,正好在我最近随着黑马74期视频敲的1个大的Demo里有这1块的内容,所以决定记录1下实现的方式。纯记录。。
2.1界面效果图
2.2layout布局文件
这里我们将“未加锁”和“已加锁”两个模块的ListView写在同1个布局文件中,用android:visibility=”“ 属性结合上方按钮的选中来决定下方是显示哪个ListView
布局文件代码以下:
<?xml version="1.0" encoding="utf⑻"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/bt_unlock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/tab_left_pressed"
android:text="未加锁"
android:textColor="#fff"
android:textSize="18sp"/>
<Button
android:id="@+id/bt_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/tab_right_default"
android:text="已加锁"
android:textColor="#fff"
android:textSize="18sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_unlock"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_unlock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="未加锁利用"/>
<ListView
android:id="@+id/lv_unlock"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_lock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/tv_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="未加锁利用"/>
<ListView
android:id="@+id/lv_lock"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
</LinearLayout>
注意到@+id/ll_lock android:visibility=”gone”,也就是通过对这两个属性的改变来控制下方的ListView到底显示的是哪个。
2.3ListView的数据来源
有了ListView我们自然就会想到,LIstView始终需要两个部份,数据源和数据适配器,也就是Adapter。首先我记录1下展现数据的来源。
//辨别已加锁利用和未加锁的利用
private void initData() {
new Thread(new Runnable() {
@Override
public void run() {
//1.获得手机中所有的利用
mAppInfoList = appInfoProvider.getAppInfoList(getApplicationContext());
//2.辨别已加锁利用和未加锁利用
mLockList = new ArrayList<AppInfo>();
mUnlockList = new ArrayList<AppInfo>();
//3.获得数据库中已加锁利用包名的集合
mDao = appLockDao.getInstance(getApplicationContext());
List<String> lockPackageList = mDao.findAll();
for (AppInfo appInfo : mAppInfoList) {
//4.如果循环到的利用的包名在数据库中,说明是已加锁了的利用
if (lockPackageList.contains(appInfo.getPackageName())) {
mLockList.add(appInfo);
} else {
mUnlockList.add(appInfo);
}
}
//5.告知主线程,数据准备好了,可使用了 消息机制
mHandler.sendEmptyMessage(0);
}
}).start();
}
其中:appInfoProvider.getAppInfoList(getApplicationContext());
mDao = appLockDao.getInstance(getApplicationContext());
List lockPackageList = mDao.findAll();
这3个是我已封装好的方法,分别用于拿得手机中所有的利用;拿到岁数据库增删改查的对象;拿到目前数据库中已有的数据。
这个意思就是说,我将已加锁的利用放到数据库中,然后将已加锁和未加锁的利用分别放到两个集合中:mLockList,mUnlockList。由于拿数据这个操作可能耗时,所以我们将这个方法放到线程中去履行。最后在利用消息机制通知主线程,数据已准备好。
2.4Adapter的设置
由于我们将两个ListVIew都写在同1个布局里,所以我们也用1个Adapter同时去配置两个LIstView,只是加上1个private boolean isLock; 这个标记,来辨别当前是配置哪个ListView。
class myAdapter extends BaseAdapter {
private boolean isLock;
//用于辨别已加锁和未加锁利用的标识 重写的构造方法
public myAdapter(boolean isLock) {
this.isLock = isLock;
}
@Override
public int getCount() {
if (isLock) {
tv_lock.setText("已加锁利用:" + mLockList.size());
return mLockList.size();
} else {
tv_unlock.setText("未加锁利用:" + mUnlockList.size());
return mUnlockList.size();
}
}
@Override
public AppInfo getItem(int position) {
if (isLock) {
return mLockList.get(position);
} else {
return mUnlockList.get(position);
}
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = View.inflate(getApplicationContext(), R.layout.listview_islock_item, null);
holder.iv_icon = (ImageView) convertView.findViewById(R.id.iv_icon);
holder.iv_lock = (ImageView) convertView.findViewById(R.id.iv_lock);
holder.tv_name = (TextView) convertView.findViewById(R.id.tv_name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final AppInfo appinfo = getItem(position);
holder.iv_icon.setBackgroundDrawable(appinfo.getIcon());
holder.tv_name.setText(appinfo.getName());
if (isLock) {
holder.iv_lock.setBackgroundResource(R.drawable.lock);
} else {
holder.iv_lock.setBackgroundResource(R.drawable.unlock);
}
return convertView;
}
}
其中getView()方法中用了convertView和holderView来优化Listview,这已是模板代码了。所以具体的HolderView就不贴出来了 。
==========================================
下面这个部份单独拎出来记录:
当我们在“未加锁”界面点击右侧的小锁时候,我们希望到达这样的1种效果:我们点击的这1个条目产生1个动画效果,向右侧滑出,然后消失,在“已加锁”界面显示出我们方才点击的哪个条目
依照这类思路,我们首先弄1个履行动画的类:
/**
* 初始化平移动画,平移本身宽度
*
* @param
* @return
* @author zfy
* @created at 2016/6/26 10:56
*/
private void initAnimation() {
mTranslateAnimation = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 1,
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 0);
mTranslateAnimation.setDuration(500);
}
接下来我们在Adapter 的getView()方法中,监听holder.iv_lock这个图标 的点击事件:下面就是我1开始出错误的地方了:
final View finalConvertView = convertView;
holder.iv_lock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//添加动画效果
finalConvertView.startAnimation(mTranslateAnimation);
if (isLock) {
//由已加锁------>未加锁
//添加动画效果
//1.已加锁的集合要删除1个,未加锁的几个要增加1个
mLockList.remove(appinfo);
mUnlockList.add(appinfo);
//2.从已加锁的数据库中删除1条数据
mDao.delete(appinfo.getPackageName());
//3.通知adapter刷新
mLockAdapter.notifyDataSetChanged();
} else {
//未加锁----->已加锁
//1.未加锁的集合要删除1个,已加锁的几个要增加1个
mLockList.add(appinfo);
mUnlockList.remove(appinfo);
//2.从已加锁的数据库中删除1条数据
mDao.insert(appinfo.getPackageName());
//3.通知adapter刷新
mUnlockAdapter.notifyDataSetChanged();
}
1切都是这么的瓜熟蒂落,点击加锁按钮–>开启动画–>从未加锁集合中删除–>添加到已加锁集合中–>添加到数据库–>通知adapter刷新。
但是我疏忽了1个问题,当我履行平移动画的时候(500ms),下面对集合的操作,更新Adapter的操作就已在履行了,并且已履行完了。所以终究实现的动画效果是,我点了1个条目,但是产生平移动画的却是下1个条目。这1点困惑了很久!所以我在这里对动画做了1个监听:当动画履行完了,才接着行对集合,数据库,和adapter刷新的操作!!
final View finalConvertView = convertView;
holder.iv_lock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//添加动画效果
finalConvertView.startAnimation(mTranslateAnimation);
//对动画履行的效果做监听,要监听到动画履行完成以后,再去移除集合中数据,操作数据库,刷新界面
mTranslateAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override //动画结束后回调方法
public void onAnimationEnd(Animation animation) {
if (isLock) {
//由已加锁------>未加锁
//添加动画效果
//1.已加锁的集合要删除1个,未加锁的几个要增加1个
mLockList.remove(appinfo);
mUnlockList.add(appinfo);
//2.从已加锁的数据库中删除1条数据
mDao.delete(appinfo.getPackageName());
//3.通知adapter刷新
mLockAdapter.notifyDataSetChanged();
} else {
//未加锁----->已加锁
//1.未加锁的集合要删除1个,已加锁的几个要增加1个
mLockList.add(appinfo);
mUnlockList.remove(appinfo);
//2.从已加锁的数据库中删除1条数据
mDao.insert(appinfo.getPackageName());
//3.通知adapter刷新
mUnlockAdapter.notifyDataSetChanged();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
});
终究写成这个模样,就完全没有问题了。
2.5对最上方两个按钮的处理
bt_unlock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.已加锁列表隐藏,未加锁列表显示
ll_lock.setVisibility(View.GONE);
ll_unlock.setVisibility(View.VISIBLE);
//2.按钮色彩切换
bt_lock.setBackgroundResource(R.drawable.tab_right_default);
bt_unlock.setBackgroundResource(R.drawable.tab_left_pressed);
}
});
bt_lock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.已加锁列表显示,未加锁列表隐藏
ll_lock.setVisibility(View.VISIBLE);
ll_unlock.setVisibility(View.GONE);
//2.按钮色彩切换
bt_lock.setBackgroundResource(R.drawable.tab_right_pressed);
bt_unlock.setBackgroundResource(R.drawable.tab_left_default);
}
});
比较简单,就不作说明了。
2.6分别设置Adapter
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//接收到消息,填充已加锁和未加锁的数据适配器
mLockAdapter = new myAdapter(true);
lv_lock.setAdapter(mLockAdapter);
mUnlockAdapter = new myAdapter(false);
lv_unlock.setAdapter(mUnlockAdapter);
}
};
这也是常规写法,不做说明
到这里就已可以实现程序锁的界面展现效果了,但是具体的业务逻辑还没有处理, 只是1个空架子。
由于明天还有《数字信号处理》的抽考,今天还要温习,所以业务逻辑这1块,留到考试考完再记录。
PS: 《数字信号处理》 这门课也是够了。整本书的傅里叶变换,离散傅里叶变换,快速傅里叶变化,Z变换,逆Z变换……TM的 ~
上次写的Widget那片文章,不知道为何,竟然1晚上有2000多人阅读。。是我的 错觉吗?我这个渣渣的技术博客1篇文章竟然访问量这么高。 还是最近很多人在学这1块的实现?
不管为何,这也让我更加坚定,坚持写技术博客的决心!