在平常使用手機的進程中,我們常常希望有這樣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塊的實現?
不管為何,這也讓我更加堅定,堅持寫技術博客的決心!