360项目-08


## 软件管理 ##android

- 文件大小的计算app

    android.text.Formatter 类能够格式化文件大小
    // 内部存储, 其实就是data目录的容量ide

        File dataDirectory = Environment.getDataDirectory();
           // 所有
        long totalSpace = dataFile.getTotalSpace();
        // 可用
        long usableSpace = dataFile.getUsableSpace();
        // 已用
        long usedSpace = totalSpace - usableSpace;
        mPdvRom.setTitle("内存: ");
        mPdvRom.setTextLeft(Formatter.formatFileSize(getApplicationContext(), usedSpace) + "已用");
        mPdvRom.setTextRight(Formatter.formatFileSize(getApplicationContext(), freeSpace) + "可用");
        mPdvRom.setProgress((int) (usedSpace * 100f / totalSpace + 0.5f)); // 四舍五入
        // SD卡
        File sdDirectory = Environment.getExternalStorageDirectory();
        // 总空间
        long sdTotalSpace = sdDirectory.getTotalSpace();
        // 剩余空间
        long sdFreeSpace = sdDirectory.getFreeSpace();
        long sdUsedSpace = totalSpace - freeSpace;
        mPdvSD.setTitle("SD卡: ");
        mPdvSD.setTextLeft(Formatter.formatFileSize(getApplicationContext(), sdUsedSpace) + "已用");
        mPdvSD.setTextRight(Formatter.formatFileSize(getApplicationContext(), sdFreeSpace) + "可用");
        mPdvSD.setProgress((int) (sdUsedSpace * 100f / sdTotalSpace+ 0.5f));布局


## 软件管理的内容部分 ##优化

- 应用程序列表先简单实现  标准listview带优化的写法动画

        private class AppAdapter extends BaseAdapter {
            @Override
            public int getCount() {
                return mDatas.size();
            }
            @Override
            public Object getItem(int position) {
                return mDatas.get(position);
            }
            @Override
            public long getItemId(int position) {
                return position;
            }
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder holder;
                if (convertView == null) {
                    convertView = View.inflate(getApplicationContext(), R.layout.item_appinfo, null);
                    holder = new ViewHolder();
                    holder.ivIcon = (ImageView) convertView.findViewById(R.id.item_appinfo_iv_icon);
                    holder.tvName = (TextView) convertView.findViewById(R.id.item_appinfo_tv_name);
                    holder.tvInstallPath = (TextView) convertView.findViewById(R.id
                            .item_appinfo_tv_install);
                    holder.tvSize = (TextView) convertView.findViewById(R.id.item_appinfo_tv_size);
                    convertView.setTag(holder);
                } else {
                    holder = (ViewHolder) convertView.getTag();
                }
                // 这里可使用 getItem 方法获取某个位置对应的对象
                AppInfo info = (AppInfo) getItem(position);
                holder.tvName.setText(info.mName);
                holder.ivIcon.setImageDrawable(info.mIcon);
                holder.tvInstallPath.setText(info.mIsInstallSD ? "SD卡安装" : "手机内存");
                holder.tvSize.setText(Formatter.formatFileSize(getApplicationContext(), info.mSize));
                return convertView;
            }
        }
        static class ViewHolder {
            ImageView ivIcon;
            TextView tvName;
            TextView tvInstallPath;
            TextView tvSize;
        }this

-- 对应的JavaBean:指针

    public class AppInfo {
        public String mName;// 应用的名称
        public String mPackageName;// 应用的包名
        public Drawable mIcon;// 应用图标
        public boolean mIsInstallSD;// 是否安装在sd卡
        public long mSize;// 应用的大小
        public boolean mIsSystem;// 是不是系统程序
    }orm


## 获取应用程序的信息##xml

- 建立一个包, engine 或者 business, 写个类, AppInfoProvider

        public class AppInfoProvider {
            public static ArrayList<AppInfo> getAllAppInfo(Context context) {
                PackageManager packageManager = context.getPackageManager();
                // 获取全部的安装包信息, PackageInfo 至关于 manifest 节点
                List<PackageInfo> packages = packageManager.getInstalledPackages(0);
                ArrayList<AppInfo> list = new ArrayList<>();
                for (PackageInfo packageInfo : packages) {
                    AppInfo appInfo = new AppInfo();
                    // 获取包名
                    appInfo.mPackageName = packageInfo.packageName;
                    // 获取应用名称
                    ApplicationInfo applicationInfo = packageInfo.applicationInfo;
                    appInfo.mName = applicationInfo.loadLabel(packageManager).toString();
                    // 获取应用图标
                    appInfo.mIcon = applicationInfo.loadIcon(packageManager);
                    // 获取应用安装包大小
                    String sourceDir = applicationInfo.sourceDir;// data/app/xxx.apk 或者 system/app/xxx.apk
                    //应用安装包
                    appInfo.mSize = new File(sourceDir).length();
                    // info.mSize = Formatter.formatFileSize(context, length);
    
                    // 是否为系统应用
                    if((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == ApplicationInfo
                            .FLAG_SYSTEM) {
                        appInfo.mIsSystem = true;
                    }else {
                        appInfo.mIsSystem = false;
                    }
    
                    // 是否为外部存储
                    // 应用能够装在sd卡上, 在清单文件根节点中配置 android:installLocation 属性便可
                    if((applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == ApplicationInfo
                            .FLAG_EXTERNAL_STORAGE) {
                        appInfo.mIsInstallSD = true;
                    }else {
                        appInfo.mIsInstallSD = false;
                    }
    
                    list.add(appInfo);
                }
                return list;
            }
        }

注意 flags 和 &, | 运算符的含义

##进度条/include标签的使用##
- 新建一个布局文件 loading:


        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:id="@+id/loading"
            android:orientation="vertical" >
        
            <ProgressBar
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:indeterminateDrawable="@drawable/progress_loading"
                android:indeterminateDuration="600" />
        
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="加载中..."
                android:textColor="#a000"
                android:textSize="16sp" />
        
        </LinearLayout>


在其余布局文件里使用 include 标签引用便可

     <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <ListView
            android:id="@+id/lv_am"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fastScrollEnabled="true" />

        <include
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            layout="@layout/loading" />
    </RelativeLayout>

- 这和直接写在布局文件里效果是同样的, 在代码中, 能够经过id找到相应的控件.

        new Thread() {
            @Override
            public void run() {
                super.run();
                // 模拟耗时操做
                SystemClock.sleep(1000);
                // 填充数据集合s
                infos = AppInfoProvider.getAllAppInfo
                        (getApplicationContext());
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mLlLoading.setVisibility(View.GONE);
                        // 给ListView设置Adapter
                        mLvApp.setAdapter(new AppAdapter());
                    }
                });
            }
        }.start();

- ListView中的条目分组显示
- 把应用信息分红用户应用和系统应用, 在数据加载完成以后分红两个集合

                  mInfos = AppInfoProvider.getAllAppInfo(getApplicationContext());
                mSysInfos = new ArrayList<AppInfo>();
                mUserInfos = new ArrayList<AppInfo>();
                // 区分用户和系统程序 分别添加到两个集合里
                for (AppInfo info : mInfos) {
                    if (info.isSys) {
                        // 系统程序
                        mSysInfos.add(info);
                    } else {
                        // 用户程序
                        mUserInfos.add(info);
                    }
                }
                mInfos.clear();// 清空以前的乱序数据
                // 先添加用户程序 而后系统程序
                mInfos.addAll(mUserInfos);
                mInfos.addAll(mSysInfos);

 

          


##ListView分隔条目/复杂ListView##  重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点

-因为多了两个分隔条目, getCount() 方法返回的数量要加2

        @Override
        public int getCount() {
           return mInfos.size() + 2; // 增长两个分隔条目
        }


- 在 getitem也要对应的改变

          @Override
            public Object getItem(int position) {
                if (position == 0 || position == mUserInfos.size() + 1) {
                    return null;
                }
                if (position < mUserInfos.size() + 1) {
                    return mInfos.get(position - 1);
                } else {
                    return mInfos.get(position - 2);
                }
            }

- 咱们要实现的效果中ListView有两个分隔条目, 区分用户应用和系统应用, 有多个条目类型的ListView. 要实现这种效果, 须要重写 Adapter 里的两个方法:

            // 返回有多少种条目类型
            @Override
            public int getViewTypeCount() {
                return 2;
            }
            // 每一个位置对应的条目的类型, 返回值表示条目类型
            @Override
            public int getItemViewType(int position) {
                // 注意返回值必须从0开始, 好比有三种类型, 就得返回 0, 1, 2.
                if (position == 0 || position == mUserDatas.size() + 1) {
                    return 0;
                } else {
                    return 1;
                }
            }

 

-getView方法中, 也得根据当前位置的条目类型返回相应的View:

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            int itemViewType = getItemViewType(position); // 先获取条目类型
            switch (itemViewType) { // 根据条目类型返回不一样的View
                case 0:
                       convertView = new TextView(getApplicationContext());
                    tv = (TextView)convertView;
                    tv.setTextColor(Color.BLACK);
                    tv.setTextSize(14);
                    tv.setPadding(4, 4, 4, 4);
                    tv.setBackgroundColor(Color.parseColor("#ffcccccc"));
                    if(position == 0) {
                        tv.setText("用户程序( " + mUserDatas.size() + " 个)");
                    }else if(position ==  mUserDatas.size() + 1) {
                        tv.setText("系统程序( " + mSystemDatas.size() + " 个)");
                    }
                    break;
                case 1:
                    ViewHolder holder;
                    if (convertView == null || convertView instanceof TextView) {
                        convertView = View.inflate(getApplicationContext(), R.layout.item_appinfo, null);
                        holder = new ViewHolder();
                        holder.ivIcon = (ImageView) convertView.findViewById(R.id.item_appinfo_iv_icon);
                        holder.tvName = (TextView) convertView.findViewById(R.id.item_appinfo_tv_name);
                        holder.tvInstallPath = (TextView) convertView.findViewById(R.id
                                .item_appinfo_tv_install);
                        holder.tvSize = (TextView) convertView.findViewById(R.id.item_appinfo_tv_size);
                        convertView.setTag(holder);
                    } else {
                        holder = (ViewHolder) convertView.getTag();
                    }
                    AppInfo info = (AppInfo) getItem(position);
                    holder.tvName.setText(info.mName);
                    holder.ivIcon.setImageDrawable(info.mIcon);
                    holder.tvInstallPath.setText(info.mIsInstallSD ? "SD卡安装" : "手机内存");
                    holder.tvSize.setText(Formatter.formatFileSize(getApplicationContext(), info.mSize));
                    break;
            }
            return convertView;
        }

##分隔条目的显示和隐藏##

在布局文件里加一个 TextView, 样式和分隔条目TextView如出一辙, 当滚动ListView的时候, 根据第一个可见条目,
作相应的显示便可.


       <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
    
            <ListView
                android:id="@+id/lv_am"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fastScrollEnabled="true" />
    
            <include
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                layout="@layout/public_loading" />
    
            <TextView
                android:id="@+id/tv_am_apphead"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#aaaaaa"
                android:padding="4px"
                android:textColor="@android:color/black"
                android:textSize="15sp"
                android:visibility="invisible" />
        </RelativeLayout>

 


-给ListView设置滚动监听: 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点 重点


       // 设置listview滑动监听 在设置的时候 默认的方法都会都一遍
        lvAm.setOnScrollListener(new OnScrollListener() {
            // 滑动状态的改变
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            // 滑动时不停的执行
            // 参1 当前listview 参2 能够见的第一个条目的索引 参3 可见的条目数量 参4 总数量
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem,
                    int visibleItemCount, int totalItemCount) {
                if (mUserInfos == null || mSysInfos == null) {
                    // 防止空指针 在设置的时候 默认的方法都会都一遍
                    return;
                }
                if (firstVisibleItem >= mUserInfos.size() + 1) {
                    // 显示系统程序 更换固定条目内容
                    tvTopSize.setText("系统程序(" + mSysInfos.size() + "个)");
                } else {
                    tvTopSize.setText("用户程序(" + mUserInfos.size() + "个)");
                }
            }
        });

 

- 默认应该是隐藏的, 当加载数据完成以后再显示:


        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // 显示ListView头部信息
                mTvHeader.setVisibility(View.VISIBLE);
                // 隐藏进度条
                mLlLoading.setVisibility(View.GONE);
                // 给ListView设置Adapter
                mLvApp.setAdapter(new AppAdapter());
            }
        });


- ListView的属性:android:fastScrollEnabled="true",
    这个属性值设置为true的话, ListView会出现快速滑动条, 默认false

##PopupWindow的基本使用##   重点 重点 重点 重点 重点 重点 重点 重点

- 它有些方法和View有点像, 有些又和Dialog比较像.
    它也是经过Window加到屏幕上的, 可是它和Dialog的又不太同样, 它的弹出位置不固定.
- 基本用法, 建立一个示例项目.


        public void popup(View v) {
            TextView contentView = new TextView(getApplicationContext());
            contentView.setTextColor(Color.RED);
            contentView.setText("我是一个弹出窗口");
            int width = ViewGroup.LayoutParams.WRAP_CONTENT;
            int height = ViewGroup.LayoutParams.WRAP_CONTENT;
            // 弹出窗口, 第一个参数表示里面要显示的View, 后两个表示宽高.
            PopupWindow popupWindow = new PopupWindow(contentView, width, height);
            // 若是想让一个弹出窗可以在点击别的区域时或者按返回键时消失, 须要调用下面两个方法.
            // 表示能够获取焦点
            popupWindow.setFocusable(true);
            // 必须设置背景, 若是实在不想要, 能够设置 new ColorDrawable(Color.TRANSPARENT)
            popupWindow.setBackgroundDrawable(new ColorDrawable(Color.GREEN));
            // 显示在某个View的左下角
            // popupWindow.showAsDropDown(mTv);
            // 显示在屏幕的某个地方, 第一个参数只须要传当前Activity里任何一个View就行.
            // popupWindow.showAtLocation(mTv, Gravity.CENTER, 0, 0);
            // 显示在某个View的左下角, 而且指定x, y轴的偏移量
            popupWindow.showAsDropDown(mTv, mTv.getWidth(), -mTv.getHeight());
        }

##在手机卫士使用PopupWindow##

- 给ListView设置 OnItemClickListener, 点击某个条目后, 在当前条目下面弹出PopupWindow.
这里能够写一个单独的方法, 把当前条目对应的View做为参数传过去. 而且记录当前点击的对象.

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            // 只有点在应用条目上, 才应该显示PopupWindow, 点在分隔标题上不显示
            // parent 只的就是ListView, getItemAtPosition内部调用的是 Adapter的 getItem
            AppInfo appInfo = (AppInfo) parent.getItemAtPosition(position);
            if (appInfo != null) {
                mCurrentAppInfo = appInfo;
                showPopupWindow(view);
            }
        }
    
               /**
             * 显示listview单条点击的弹出框
             *
             * @param view
             */
            private void showPop(View view) {
                // 为空的时候再建立对象
                if (pop == null) {
                    // 设置宽高为包裹内容
                    int width = LayoutParams.WRAP_CONTENT;
                    int height = LayoutParams.WRAP_CONTENT;
                    View contentView = View.inflate(getApplicationContext(), R.layout.popup_am,
                            null);
                    contentView.findViewById(R.id.tv_popam_uninstall).setOnClickListener(this);
                    contentView.findViewById(R.id.tv_popam_open).setOnClickListener(this);
                    contentView.findViewById(R.id.tv_popam_share).setOnClickListener(this);
                    contentView.findViewById(R.id.tv_popam_info).setOnClickListener(this);
        
                    pop = new PopupWindow(contentView, width, height);
                    // 能够获取焦点
                    pop.setFocusable(true);
                    // 设置背景 只有设置了背景,点击 外部区域或者返回键 才会消失
                    pop.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));// 设置背景透明
                    // anchor 锚点 抛锚 让PopupWindow显示在指定的anchor下方
                    // pop.showAsDropDown(view);
        
                    // 设置动画弹出方式
                    pop.setAnimationStyle(R.style.PopAnimation);
                }
                pop.showAsDropDown(view, 60, -view.getHeight());
                // 参1 传入activity里任意一个view就能够
                // pop.showAtLocation(mtv, Gravity.LEFT | Gravity.CENTER_VERTICAL, 50,
                // 0);
            }

- 动画样式  pop.setAnimationStyle(R.style.PopAnimation);
这里能够仿照输入法的动画样式, 本身写一个, 在 styles.xml中:

        <style name="PopAnimation">
            <item name="android:windowEnterAnimation">@anim/pop_am_enter</item>
            <item name="android:windowExitAnimation">@anim/pop_am_exit</item>
        </style>

        <?xml version="1.0" encoding="utf-8"?>
            <set xmlns:android="http://schemas.android.com/apk/res/android"
                android:shareInterpolator="false" >
            
                <translate
                    android:duration="@android:integer/config_shortAnimTime"
                    android:fromXDelta="100%"
                    android:interpolator="@interpolator/overshoot"
                    android:toXDelta="0" />
            
                <alpha
                    android:duration="@android:integer/config_shortAnimTime"
                    android:fromAlpha="0.5"
                    android:interpolator="@interpolator/decelerate_cubic"
                    android:toAlpha="1.0" />
            
            </set>


            <?xml version="1.0" encoding="utf-8"?>
                <set xmlns:android="http://schemas.android.com/apk/res/android"
                    android:shareInterpolator="false" >
                
                    <translate
                        android:duration="@android:integer/config_shortAnimTime"
                        android:fromXDelta="0"
                        android:interpolator="@interpolator/anticipate"
                        android:toXDelta="100%" />
                
                    <alpha
                        android:duration="@android:integer/config_shortAnimTime"
                        android:fromAlpha="1.0"
                        android:interpolator="@interpolator/accelerate_cubic"
                        android:toAlpha="0.0" />
                
                </set>

- 注意使用了两个interpolator文件:

        <overshootInterpolator xmlns:android="http://schemas.android.com/apk/res/android"/>
        <anticipateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"/>

# 卸载, 打开, 分享, 信息#
- 点击PopupWindow里面的文字时, 实现相应的功能

        /**
         * 显示app信息页面
         *
         * @param packageName
         */
        private void showInfo(String packageName) {
            // <action android:name="android.settings.APPLICATION_DETAILS_SETTINGS"
            // />
            // <category android:name="android.intent.category.DEFAULT" />
            // <data android:scheme="package" />
            Intent intent = new Intent();
            intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.setData(Uri.parse("package:" + packageName));
            startActivity(intent);
        }
    
        /**
         * 分享app
         */
        private void shareApp() {
            // <action android:name="android.intent.action.SEND" />
            // <category android:name="android.intent.category.DEFAULT" />
            // <data android:mimeType="text/plain" />
    
            // sharesdk mob 友盟 极光 百度云推送
    
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_SEND);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.setType("text/plain");
            intent.putExtra(Intent.EXTRA_TEXT, "分享一个app,,:" + mCurrentInfo.name);
            startActivity(intent);
        }
    
        /**
         * 打开一个app
         *
         * @param packageName
         */
        private void openApp(String packageName) {
            PackageManager pm = getPackageManager();
            // 返回启动页面的intent
            Intent openIntent = pm.getLaunchIntentForPackage(packageName);
            // 有些应用没有页面 只有后台程序 须要判断空
            if (openIntent != null) {
                startActivity(openIntent);
            }
        }
    
        /**
         * 卸载app
         *
         * @param packageName
         */
        private void unInstallApp(String packageName) {
            // <action android:name="android.intent.action.VIEW" />
            // <action android:name="android.intent.action.DELETE" />
            // <category android:name="android.intent.category.DEFAULT" />
            // <data android:scheme="package" />
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_DELETE);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.setData(Uri.parse("package:" + packageName));
            startActivityForResult(intent, REQUESTCODE_UNINSTALL);
        }
    
        

## 卸载后的处理 ##
- 简单的作法, 点击卸载时, startActivityForResult, 从卸载界面回来的时候, 从新获取一遍数据便可.  
    注意获取数据以前, 先清空以前的数据集合.

       @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == REQUESTCODE_UNINSTALL) {// 从卸载页面返回
                // Activity.RESULT_OK
                // resultCode
                // System.out.println("resultCode ==" + resultCode);
    
                // 重新获取数据
                // 获取数据前先清空
                    userAppInfos.clear();
                    sysAppInfos.clear();
                    appInfos = AppInfoProvider.getAllAppInfo(getApplicationContext());
                    // 把用户程序和系统程序分开
                    for (AppInfo info : appInfos) {
                        if (info.isSystem) {
                            sysAppInfos.add(info);
                        } else {
                            userAppInfos.add(info);
                        }
                    }
                    appAdapter.notifyDataSetChanged();
            }
        }


- 比较高级的作法, 监听系统卸载应用的广播:  
  在 onCreate 中注册广播接收者:

        // 注册应用卸载的广播
        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addDataScheme("package");
        registerReceiver(mPackageReceiver, filter);

- 在 onDestroy 中解除注册:

        unregisterReceiver(mPackageReceiver);

 对应的广播接收者:


        private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                System.out.println("接收到卸载广播");
                String dataString = intent.getDataString();
                System.out.println("卸载了:" + dataString);
                String packageName = dataString.replace("package:", "");
                // 只须要遍历用户集合就能够了, 由于系统的删不掉
                // 一边遍历一遍移除须要使用 iterator
                ListIterator<AppInfo> iterator = mUserDatas.listIterator();
                while (iterator.hasNext()) {
                    AppInfo next = iterator.next();
                    if (next.packageName.equals(packageName)) {
                        // 移除
                        iterator.remove();
                        mUserInfos.remove(info);
                        break;
                    }
                }
                // 刷新ListView
                mAdapter.notifyDataSetChanged();
            }
        };


    但其实使用广播是不靠谱的, 由于有的系统不发这个广播...

- bug
    
    点击分割条目的bug   单条点击事件

    if (position == 0 || position == mUserInfos.size() + 1) {
        //若是点击的是分割条目 不处理
        return;
    }

    把固定条目变成可点击 处理透过点击的bug           android:clickable="true"

相关文章
相关标签/搜索