Launcher中的App索引——Apps字母索引组件
来源:互联网 发布:杂志软件哪个好 编辑:程序博客网 时间:2024/05/17 01:14
本文介绍Launcher中的Apps字母索引功能,什么是字母索引呢?
Google的原生的Launcher是用抽屉来装所有App的,但是抽屉真的方便吗?最近市场上流行的好多轻量级桌面都纷纷抛弃了抽屉,用Apps索引来代替。
如图:
我们来分析一下然后自己做一个
1.整体可以重写RelativeLayout
2.右边的滑动的字母条可以重写LinearLayout
3.中间装App的用ListView,并重写一个Item
4.Item重写LinearLayout
如下:
1.AppsCustomsizeIndexView.java 整体组件
初始化Listiew、重写BaseAdapter
初始化自定义的AppsIndexLayout 、初始化时获取所有APP的title字段,生成字母List,里面不能有重复,然后排序,准备在AppsIndexLayout中使用。
XML:
<?xml version="1.0" encoding="utf-8"?><com.ola.launcher.AppsCustomizeIndexView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:launcher="http://schemas.android.com/apk/res/com.ola.launcher" android:id="@+id/apps_customize_indexview" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:visibility="visible" launcher:itemIconHeight="50dp" launcher:itemIconWidth="50dp" >//这两个属性暂时没有用,可以不加 <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:focusable="true" android:textSize="50dp" /> <ListView android:id="@+id/apps_customize_listview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/textview" android:layout_toLeftOf="@+id/apps_customize_indexlayout" android:background="@null" android:divider="@null" android:scrollbars="none" >//中间装app的ListView </ListView> <com.ola.launcher.AppsIndexLayout android:id="@+id/apps_customize_indexlayout" android:layout_width="@dimen/apps_custom_indexview_width" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_below="@+id/textview" android:layout_marginBottom="@dimen/apps_custom_indexview_marginbottom" android:background="@android:color/holo_blue_dark" > </com.ola.launcher.AppsIndexLayout>//右边的字母条</com.ola.launcher.AppsCustomizeIndexView>
代码:
public class AppsCustomizeIndexView extends RelativeLayout implements ScrollListener {private TextView mTextView;private AppsIndexLayout mIndexLayout;//字母条private ListView mListView;private AppsAdapter mAppsAdapter;private ArrayList<String> mKeys = new ArrayList<String>();//字母条需要的数据private HashMap<String, ArrayList<ApplicationInfo>> mKeyItem = new HashMap<String, ArrayList<ApplicationInfo>>();//app数据private ArrayList<ApplicationInfo> mIndexApps = new ArrayList<ApplicationInfo>();//零时装app的Listprivate ArrayList<ApplicationInfo> mApplicationInfos;String mEmpty = "";String mRencent = "⊙";String mOther = "#";public AppsCustomizeIndexView(Context context, AttributeSet attrs) {super(context, attrs);}public AppsCustomizeIndexView(Context context) {super(context);}protected void onFinishInflate() {// TODO Auto-generated method stubsuper.onFinishInflate();mIndexLayout = (AppsIndexLayout) findViewById(R.id.apps_customize_indexlayout);mListView = (ListView) findViewById(R.id.apps_customize_listview);mIndexLayout.setOnScrollListener(this);mTextView = (TextView) findViewById(R.id.textview);}@SuppressLint("ClickableViewAccessibility")public boolean onTouchEvent(MotionEvent event) {return true;}private void setTestText(String s) {mTextView.setText(s);}public void setDate(ArrayList<ApplicationInfo> infos) {this.mApplicationInfos = infos;setTestText(mApplicationInfos.size() + "");mKeys = getKeyFromApps();mIndexLayout.setDate(mKeys);mAppsAdapter = new AppsAdapter(mKeys, mKeyItem, getContext());mListView.setAdapter(mAppsAdapter);}@SuppressLint("DefaultLocale")//通过遍历所有AppsList的App的title字段,取出第一个字符,生成一个Listprivate ArrayList<String> getKeyFromApps() {ArrayList<String> mIndexKey = new ArrayList<String>();String language = Locale.getDefault().getLanguage();Pattern pattern = Pattern.compile("^[A-Za-z]+$");for (int i = 0; i < mApplicationInfos.size(); i++) {String key = mApplicationInfos.get(i).title.toString().trim().toUpperCase().charAt(0) + mEmpty;if (pattern.matcher(key).matches()) {//匹配大小写英文字母if (!mIndexKey.contains(key)) {mIndexKey.add(key);mIndexApps = new ArrayList<ApplicationInfo>();mKeyItem.put(key, mIndexApps);} else {mIndexApps = mKeyItem.get(key);}if (mIndexApps != null) {mIndexApps.add(mApplicationInfos.get(i));}} else {if (Locale.CHINA.getLanguage().equalsIgnoreCase(language)) {char c = key.toCharArray()[0];if (Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS.equals(Character.UnicodeBlock.of(c))) { //中文时候的处理、还有其他语言考虑} else {addOther(mIndexKey, mKeyItem, mApplicationInfos.get(i), mOther);//乱码时候处理}} else {String o = key;if (!mIndexKey.contains(o)) {mIndexKey.add(o);mIndexApps = new ArrayList<ApplicationInfo>();mKeyItem.put(o, mIndexApps);} else {mIndexApps = mKeyItem.get(o);}if (mIndexApps != null) {mIndexApps.add(mApplicationInfos.get(i));}}}}// mIndexKey.add(mRencent);// mIndexKey.add(mOther);Collections.sort(mIndexKey);addOther(mIndexKey, mKeyItem, mApplicationInfos.get(0), mOther);addOther(mIndexKey, mKeyItem, mApplicationInfos.get(0), mRencent);return mIndexKey;}@Overridepublic void onDrag(String key) {mListView.setSelection(findPosFromList(key));}private void addOther(ArrayList<String> keystrings, HashMap<String, ArrayList<ApplicationInfo>> keyitem,ApplicationInfo apps, String string) {ArrayList<ApplicationInfo> mInfos;if (!keystrings.contains(string)) {keystrings.add(0, string);mInfos = new ArrayList<ApplicationInfo>();keyitem.put(string, mInfos);} else {mInfos = keyitem.get(string);}if (mInfos != null) {mInfos.add(apps);}}public int findPosFromList(String key) {for (int i = 0; i < mKeys.size(); i++) {if (key.equals(mKeys.get(i))) {return i;}}return 0;}class AppsAdapter extends BaseAdapter {private ArrayList<String> stringsArray;private HashMap<String, ArrayList<ApplicationInfo>> mKeyItem;Context context;public AppsAdapter(ArrayList<String> stringsArray, HashMap<String, ArrayList<ApplicationInfo>> mKeyItem, Context context) {this.stringsArray = stringsArray;this.context = context;this.mKeyItem = mKeyItem;}@Overridepublic int getCount() {return stringsArray.size();}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@SuppressLint("InflateParams")@Overridepublic View getView(int position, View convertView, ViewGroup parent) {if (convertView == null) {convertView = LayoutInflater.from(context).inflate(R.layout.apps_customize_indexview_item, null);}((AppsCustomizeIndexViewItemLayout) convertView).setKeyString(stringsArray.get(position).toString());((AppsCustomizeIndexViewItemLayout) convertView).setMeasure(mKeyItem.get(stringsArray.get(position)).size());((AppsCustomizeIndexViewItemLayout) convertView).setContent(mKeyItem.get(stringsArray.get(position)));return convertView;}}}
2.AppsIndexLayout.java 右边的字母条组件
我们来分析一下:
仅仅是显示一排字母的话,我们就让他继承LinearLayout,并且设置排列方式为竖直,然后在LinearLayout中添加上若干个TextView就可以,用TextView来显示具体的字母。
再自己定义一个接口ScrollListener,用来在触摸事件中去触发该接口的方法并传递参数,通过该方法去控制另外组件的状态变化
触摸过程中调用接口的方法,并且计算位置,让触摸周围的TexView高亮显示
java:
public class AppsIndexLayout extends LinearLayout {public ScrollListener mDragListener;private ArrayList<String> mIndexKey;private TextView mTextView;private int mViewHeight;private Rect mHitRect = new Rect();private String mColor3 = "#B8B3AE";private String mColor2 = "#C7C5BD";private String mColor1 = "#FFFFFF";public AppsIndexLayout(Context context, AttributeSet attrs) {super(context, attrs);setOrientation(VERTICAL);setGravity(Gravity.CENTER_HORIZONTAL);}// @Override// protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// super.onMeasure(widthMeasureSpec, heightMeasureSpec);// int result_w = mearWidth(widthMeasureSpec);// int result_h = mearHeight(heightMeasureSpec);//// setMeasuredDimension(result_w, result_h);// }// private int mearWidth(int widthMeasureSpec) {// int result = 0;// int specMode = MeasureSpec.getMode(widthMeasureSpec);// int spacSize = MeasureSpec.getSize(widthMeasureSpec);// if (specMode == MeasureSpec.EXACTLY) {// result = spacSize;// } else {// result = getResources().getInteger(R.dimen.apps_custom_indexview_width);// if (specMode == MeasureSpec.AT_MOST) {// result = Math.min(result, spacSize);// }// }// return result;// }// private int mearHeight(int heightMeasureSpec) {// int result = 0;// int specMode = MeasureSpec.getMode(heightMeasureSpec);// int spacSize = MeasureSpec.getSize(heightMeasureSpec);// if (specMode == MeasureSpec.EXACTLY) {// result = spacSize;// } else {// result = getResources().getDisplayMetrics().heightPixels;// if (specMode == MeasureSpec.AT_MOST) {// result = Math.min(result, spacSize);// }// }// mViewHeight = result;// return result;// }public void setDate(ArrayList<String> indexkey) {int h = getResources().getDisplayMetrics().heightPixels;mIndexKey = indexkey;LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, h / (indexkey.size() + 6));for (int i = 0; i < mIndexKey.size(); i++) {TextView textView = new TextView(getContext());textView.setGravity(Gravity.CENTER);textView.setTextSize(12);textView.setText(mIndexKey.get(i).toString());addView(textView, layoutParams);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_UP:case MotionEvent.ACTION_MOVE:default:getKeyString(event);break;}return true;}private void getKeyString(MotionEvent event) {int x = (int) event.getX();int y = (int) event.getY();for (int i = 0; i < getChildCount(); i++) {if (getViewByEvent(x, y, getChildAt(i))) {((TextView) getChildAt(i)).setTextColor(Color.parseColor(mColor1));mDragListener.onDrag(((TextView) getChildAt(i)).getText().toString());//调用接口的方法,参数传递我们当前的TextView的文本if (i + 1 < getChildCount()) {((TextView) getChildAt(i + 1)).setTextColor(Color.parseColor(mColor1));//计算触摸时的TextView位置,在越界的情况下让其上下的都高亮显示for (int j = i + 2; j < getChildCount(); j++) {((TextView) getChildAt(j)).setTextColor(Color.parseColor(mColor2));}}if (i - 1 > 0) {((TextView) getChildAt(i - 1)).setTextColor(Color.parseColor(mColor1));for (int j = 0; j < i - 2; j++) {((TextView) getChildAt(j)).setTextColor(Color.parseColor(mColor2));}}}}}private boolean getViewByEvent(int x, int y, View v) {v.getHitRect(mHitRect);int i = (mHitRect.left + mHitRect.right) / 2;return mHitRect.contains(i, y);}public void addChild(TextView view) {addView(view);}public void setOnScrollListener(ScrollListener dragListener) {this.mDragListener = dragListener;}interface ScrollListener {public void onDrag(String key);}}
3.AppsCustomsizeIndexViewItemLayout.java
ListView中的高矮不一的Item,里面显示大字母的TextView,显示具体App的GridLayout
GridLayout可以设置行列
Xml:apps_customsize_indexview_item
<?xml version="1.0" encoding="utf-8"?><com.ola.launcher.AppsCustomizeIndexViewItemLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/holo_orange_light" > <TextView android:id="@+id/apps_index_item_key" android:layout_width="@dimen/apps_custom_indexview_key_width" android:layout_height="@dimen/apps_custom_indexview_key_height" android:layout_marginLeft="@dimen/apps_custom_indexview_key_marginleft" android:layout_marginTop="@dimen/apps_custom_indexview_key_margintop" android:background="@drawable/apps_index_item_key_bg" android:textColor="@android:color/white" android:gravity="center" android:textSize="@dimen/apps_custom_indexview_key_textsize" /> <!-- <GridLayout android:id="@+id/apps_index_item_grid" android:layout_width="match_parent" android:layout_height="wrap_content" > </GridLayout> --></com.ola.launcher.AppsCustomizeIndexViewItemLayout>
Java:
public class AppsCustomizeIndexViewItemLayout extends LinearLayout implements OnClickListener {private TextView mKeyView;private GridLayout mAppsGridLayout;private int mGridCellX = 4;Launcher mLauncher;private IconCache mIconCache;public AppsCustomizeIndexViewItemLayout(Context context, AttributeSet attrs) {super(context, attrs);mLauncher = (Launcher) context;mIconCache = ((LauncherApplication) context.getApplicationContext()).getIconCache();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}private int onMeasureWidth(int widthMeasureSpec) {int result = 0;int specMode = MeasureSpec.getMode(widthMeasureSpec);int specSize = MeasureSpec.getSize(widthMeasureSpec);if (specMode == MeasureSpec.EXACTLY) {result = specSize;} else {result = specSize;}return result;}private int onMeasureHeight(int heightMeasureSpaec) {int result = 0;int specMode = MeasureSpec.getMode(heightMeasureSpaec);int spacSize = MeasureSpec.getSize(heightMeasureSpaec);if (specMode == MeasureSpec.EXACTLY) {result = spacSize;} else {result = spacSize;}return result;}@Overrideprotected void onFinishInflate() {super.onFinishInflate();mKeyView = (TextView) findViewById(R.id.apps_index_item_key);// mAppsGridLayout = (GridLayout)// findViewById(R.id.apps_index_item_grid);mAppsGridLayout = new GridLayout(getContext());mAppsGridLayout.setColumnCount(mGridCellX);addView(mAppsGridLayout);}public void setKeyString(String key) {mKeyView.setText(key);}public void setGridBackground(int c) {mAppsGridLayout.setBackgroundColor(c);}public void setMeasure(int count) {}public void setContent(ArrayList<ApplicationInfo> infos) {mAppsGridLayout.removeAllViews();IconTextView itemView;for (int i = 0; i < infos.size(); i++) {// itemView = (PagedViewIcon)// LayoutInflater.from(getContext()).inflate(R.layout.apps_customize_application,// null);itemView = new IconTextView(getContext());// itemView.applyFromApplicationInfo(infos.get(i), true, null);itemView.setIcon(new FastBitmapDrawable(infos.get(i).iconBitmap));itemView.setText(infos.get(i).title);// itemView.setOnClickListener(this);mAppsGridLayout.addView(itemView, Math.min(1, mAppsGridLayout.getChildCount()), new LayoutParams(140, 200));}}@Overridepublic void onClick(View v) {ApplicationInfo info = (ApplicationInfo) v.getTag();startActivity(info, v);}public void startActivity(ApplicationInfo info, View v) {final Intent intent = info.intent;int[] pos = new int[2];v.getLocationOnScreen(pos);intent.setSourceBounds(new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight()));if (!mLauncher.startActivitySafely(v, intent, null)) {}}class IconTextView extends TextView {//显示AppItem Viewpublic IconTextView(Context context) {super(context);setGravity(Gravity.CENTER_HORIZONTAL);setPadding(10, 20, 10, 10);// setTextColor(Color.BLACK);}public void setIcon(Drawable d) {setCompoundDrawablesWithIntrinsicBounds(null, d, null, null);//TextView上下左右设置图片的,这里我们只给top设置}}}
最后们来看看功能的实现效果:
- Launcher中的App索引——Apps字母索引组件
- 字母索引组件
- 字母索引查询ListView组件
- 字母索引查询ListView组件
- 字母索引查询ListView组件
- 字母索引——自定义点击事件
- Android 自定义View——联系人右侧字母索引
- C#中的索引器——双重索引器
- 按字母索引
- ListView 字母索引查询
- 联系人字母索引实现
- AlphabetIndexer字母索引器
- android 字母索引 listview
- 字母索引搜索ListView
- 自定义字母索引View
- listview字母索引查找
- 字母索引表
- 自定义通讯录字母索引
- codevs石子归并 动态规划
- 14 多对一关联关系的映射与原理分析
- 组播技术
- supervisor不产生日志
- 北京SEO优化服务:电子商务网站该如何做SEO优化?
- Launcher中的App索引——Apps字母索引组件
- oracle 查询 分页
- 【猫猫的Unity Shader之旅】之初识屏幕特效
- 一次归档日志被删除导致offline的datafile 无法访问的问题
- 黑马程序员-----String,StringBuffer,StringBulider
- C实现万年历
- OpenCV-2.4.2 安装三步曲
- 百度蜘蛛抓取规则 Baiduspider
- Linux平台下使用rman进行oracle数据库迁移