android---常驻悬浮框效果的实现

一.效果展示

这里写图片描述
这里写图片描述
这里写图片描述

我不会做动态图片,现在图书馆也没有网络(PS:图书馆的100M网线接口一直都可以用的,但那时不知道为什么从昨天开始用不了了,于是只有手机放热点了。。心痛~),所以就截取三张图片,将就着看看。

注意顶部灰色的条目框,在上划的过程中的变化
这种效果在手机QQ联系人列表也可以见到。记录下来,避免以后忘记
下面就以我最近做的项目的软件管理功能作为例子,简单记录一下实现方法(只分析常驻悬浮框,其余展示逻辑不做分析

二.布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        style="@style/TitleStyle"
        android:text="软件管理" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp">

        <TextView
            android:id="@+id/tv_memory"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="磁盘可用" />

        <TextView
            android:id="@+id/tv_sd_memory"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="SD卡可用" />
    </RelativeLayout>


    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ListView
            android:id="@+id/lv_app_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        </ListView>

        <TextView
            android:id="@+id/tv_des"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#ccc"
            android:textColor="#fff"
            android:textSize="16sp" />


    </FrameLayout>


</LinearLayout>

布局效果:
这里写图片描述

这个layout文件比较简单,就是在FrameLayout帧布局这块要注意下,帧布局下的空间都是一层一层叠加的,所以显示的效果是在LIstView上层覆盖了一个Textview。

三.Activity中的业务逻辑

实现这种效果的重点是在Adapter中,代码贴出来如下:

 class MyAdapter extends BaseAdapter {

        //获取数据适配器中条目类型的总数,修改成两种(纯文本,图片+文字)
        @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount() + 1;
        }

        //指定索引指向的条目类型,条目类型状态码指定(0(复用系统),1)
        @Override
        public int getItemViewType(int position) {
            if (position == 0 || position == mCustomerList.size() + 1) {
                //返回0,代表纯文本条目的状态码
                return 0;
            } else {
                //返回1,代表图片+文本条目状态码
                return 1;
            }
        }

        //listView中添加两个描述条目  (纯文本)
        @Override
        public int getCount() {
            return mCustomerList.size()+1 + mSystemList.size()+1;
        }

        @Override
        public AppInfo getItem(int position) {
            if (position == 0 || position == mCustomerList.size() + 1) {
                return null;
            } else {
                if (position < mCustomerList.size() + 1) {
                    return mCustomerList.get(position - 1);
                } else {
                    //返回系统应用对应条目的对象
                    return mSystemList.get(position - mCustomerList.size() - 2);
                }
            }
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            int type = getItemViewType(position);

            if (type == 0) {
                //展示灰色纯文本条目
                ViewTitleHolder holder = null;
                if (convertView == null) {
                    convertView = View.inflate(getApplicationContext(), R.layout.listview_app_item_title, null);
                    holder = new ViewTitleHolder();
                    holder.tv_title = (TextView) convertView.findViewById(R.id.tv_title);
                    convertView.setTag(holder);
                } else {
                    holder = (ViewTitleHolder) convertView.getTag();
                }
                if (position == 0) {
                    holder.tv_title.setText("用户应用(" + mCustomerList.size() + ")");
                } else {
                    holder.tv_title.setText("系统应用(" + mSystemList.size() + ")");
                }
                return convertView;
            } else {
                //展示图片+文字条目
                ViewHolder holder = null;
                if (convertView == null) {
                    convertView = View.inflate(getApplicationContext(), R.layout.listview_app_item, null);
                    holder = new ViewHolder();
                    holder.iv_icon = (ImageView) convertView.findViewById(R.id.iv_icon);
                    holder.tv_name = (TextView) convertView.findViewById(R.id.tv_name);
                    holder.tv_path = (TextView) convertView.findViewById(R.id.tv_path);
                    convertView.setTag(holder);
                } else {
                    holder = (ViewHolder) convertView.getTag();
                }
                holder.iv_icon.setBackgroundDrawable(getItem(position).getIcon());
                holder.tv_name.setText(getItem(position).getName());
                if (getItem(position).isSdCard()) {
                    holder.tv_path.setText("sd卡应用");
                } else {
                    holder.tv_path.setText("手机应用");
                }
                return convertView;
            }
        }
    }

两个ViewHolder用于优化listView

 private static class ViewHolder {
        ImageView iv_icon;
        TextView tv_name;
        TextView tv_path;

    }

    private static class ViewTitleHolder {
        TextView tv_title;

    }

重写了BaseAdapter的两个方法,如下:在一般做展示ListView中是不会用到的,但是在常驻悬浮框的效果中,这两个方法发是很关键的!

 //获取数据适配器中条目类型的总数,修改成两种(纯文本,图片+文字)
        @Override
        public int getViewTypeCount() {
            return super.getViewTypeCount() + 1;
        }

        //指定索引指向的条目类型,条目类型状态码指定(0(复用系统),1)
        @Override
        public int getItemViewType(int position) {
            if (position == 0 || position == mCustomerList.size() + 1) {
                //返回0,代表纯文本条目的状态码
                return 0;
            } else {
                //返回1,代表图片+文本条目状态码
                return 1;
            }
        }

super.getViewTypeCount()默认返回值为1,所以需要+1,View的类型有2种。getItemViewType(int position) 此方法根据条目的位置,给他们分别添加上索引值,纯文本的返回0,图片加文本,返回1;两种VIew如下:

纯文本的View            R.layout.listview_app_item_title
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_title"
        android:textSize="16sp"
        android:textColor="#fff"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ccc" />

</LinearLayout>
图片加文本的View       R.layout.listview_app_item
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/iv_icon"
        android:background="@mipmap/ic_launcher"
        android:layout_width="45dp"
        android:layout_height="45dp" />
    <TextView
        android:id="@+id/tv_name"
        android:text="应用名称"
        android:textSize="18dp"
        android:layout_toRightOf="@+id/iv_icon"
        android:layout_width="wrap_content"
        android:textColor="#000"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/tv_path"
        android:textSize="18dp"
        android:layout_toRightOf="@+id/iv_icon"
        android:text="应用安装路径"
        android:textColor="#000"
        android:layout_below="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />



</RelativeLayout>

说到这里应该就知道了。常驻悬浮框也是作为ListView的一个条目展示出来的,只是要在Adapter中设置两种条目的布局

在ListView的滚动过程中修改中,帧布局里的TextView的展示

private void initList() {
        lv_app_list = (ListView) findViewById(R.id.lv_app_list);
        tv_des = (TextView) findViewById(R.id.tv_des);


        lv_app_list.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {


            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                //滚动过程中调用方法
                //AbsListView中view就是listView对象
                //firstVisibleItem第一个可见条目索引值
                //visibleItemCount当前一个屏幕的可见条目数
                //totalItemCount总共条目总数

                if (mCustomerList != null && mSystemList != null) {
                    if (firstVisibleItem >= mCustomerList.size() + 1) {
                        //滚动到了系统条目
                        tv_des.setText("系统应用(" + mSystemList.size() + ")");

                    } else {
                        //滚动到了用户应用条目
                        tv_des.setText("用户应用(" + mCustomerList.size() + ")");
                    }
                }
            }
        });

到这个部分,就可以知道了,所谓的常驻悬浮框只是一个“障眼法”,在滚动的过程中去改变帧布局中最上层的TextView的展示文字,从实现效果上看,就好像实现了常驻悬浮框的效果。

四.后记

写的比较笼统,可能只有我自己看懂了。。 就简单的记录下吧

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值