关于ListView的Item中嵌套ProgressBar的那些事

这几天一直在为了这个Listview嵌套Progressbar的情况伤脑筋,可是项目中又不能少了这些功能,上周老大说要在项目中增加一个图片上传的功能,我一听,这好啊,可以实现客户与服务器的交互,又能增加客户体验,不是两全其美么?哈哈,不过问题来了,在我使用Progressbar在Listview中的时候发现并不是自己想象的那么顺利,因为牵扯到很多UI错乱的情况,这可急坏我了,怎么办?只能自己好想办法解决了
我相信你大家遇到这样的情况也同样很头疼,接下来就让我们一起探讨,怎样在ListView中嵌套,效果类似于QQ空间的图片上传效果:

先看item的布局文件吧:

<?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:layout_margin="@dimen/margin_10"
    android:orientation="horizontal" >

    <ImageView
        android:id="@id/iv_photo"
        android:layout_width="@dimen/layout_80"
        android:layout_height="@dimen/layout_80"
        android:layout_gravity="center_vertical"
        android:contentDescription="@string/hello_world"
        android:scaleType="centerCrop" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/tv_photo_name"
            style="@style/text_style"
            android:layout_marginLeft="@dimen/margin_10"
            android:layout_marginRight="@dimen/margin_10"
            android:textColor="@color/black" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/margin_5" >

            <TextView
                android:id="@+id/tv_progress"
                style="@style/text_style"
                android:layout_alignParentRight="true"
                android:layout_marginLeft="@dimen/margin_10"
                android:layout_marginRight="@dimen/margin_10"
                android:textColor="@color/black"
                android:visibility="invisible" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/margin_10"
            android:layout_marginRight="@dimen/margin_10" >

            <ProgressBar
                android:id="@+id/progressbar"
                style="@style/StyleProgressBarMini"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/shape_progressbar_bg"
                android:visibility="gone" />

            <TextView
                android:id="@+id/tv_loading"
                style="@style/text_style"
                android:text="@string/loading"
                android:textColor="@color/black" />
        </RelativeLayout>
    </LinearLayout>

</LinearLayout>

布局文件很简单,就是一个进度条,外加一个图片控件,还有几个textview,主要是用来模仿QQ空间上传效果,每次只对第一个图片进行上传,其余的图片进行等待,第一张上传完毕后从list中移除,并且刷新Adapter

在实现这部分功能的时候还需要增加一个实体类,来保存下载状态,和进度条的进度,实体类如下:

public class UploadPhoto extends Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String path; //图片路径
    private boolean isDownload; //下载状态
    private int progress; //进度
    public String getPath() {
        return path;
    }
    public void setPath(String path) {
        this.path = path;
    }
    public boolean isDownload() {
        return isDownload;
    }
    public void setDownload(boolean isDownload) {
        this.isDownload = isDownload;
    }
    public int getProgress() {
        return progress;
    }
    public void setProgress(int progress) {
        this.progress = progress;
    }

}

我们再看一下这个时候的adapter是怎么样写:

public class UploadPhotoAdapter extends BaseAdapter{


    ViewHolder holder = null;
    private List<UploadPhoto> list = new ArrayList<UploadPhoto>();
    private Context mContext;

    public UploadPhotoAdapter(Context mContext, List<UploadPhoto> list) {
        this.list = list;
        this.mContext = mContext;
        int maxMemory = (int)Runtime.getRuntime().maxMemory();
        int chcheSize = maxMemory / 8;
        FileUtils fileUtil = new FileUtils(mContext, Common.CACHE_DIR);
        utils = new BitmapUtils(mContext, fileUtil.getCacheDir(), chcheSize);
    }


    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return list.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View view = convertView;
        if (view == null) {

            LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.upload_photo_list_item, parent, false);
            holder = new ViewHolder();
            holder.tv_name = (TextView) view.findViewById(R.id.tv_photo_name);
            holder.tv_loading = (TextView) view.findViewById(R.id.tv_loading);
            holder.iv_photo = (ImageView) view.findViewById(R.id.iv_photo);
            holder.tv_progress = (TextView) view.findViewById(R.id.tv_progress);
            holder.progressbar = (ProgressBar) view.findViewById(R.id.progressbar);

            LayoutParams mLayoutParams = holder.iv_photo.getLayoutParams();
            mLayoutParams.width = (int) (Common.Width / 5);
            mLayoutParams.height = (int) (Common.Width / 5);
            holder.iv_photo.setLayoutParams(mLayoutParams);

            view.setTag(holder);

        } else {
            holder = (ViewHolder) view.getTag();
        }

        UploadPhoto item = (UploadPhoto) getItem(position);

        if (item != null) {

            utils.display(holder.iv_photo, item.getPath());
            String name = item.getPath().substring(item.getPath().lastIndexOf("/") + 1, item.getPath().lastIndexOf("."));
            holder.tv_name.setText(name);
            //这里对下载状态进行判断,是否显示进度条
            if (item.isDownload()) {

                holder.progressbar.setVisibility(View.VISIBLE);
                holder.tv_loading.setVisibility(View.GONE);
                holder.tv_progress.setVisibility(View.VISIBLE);

            }else {

                holder.progressbar.setVisibility(View.GONE);
                holder.tv_loading.setVisibility(View.VISIBLE);
                holder.tv_progress.setVisibility(View.GONE);

            }

        }

        return view;
    }

    public class ViewHolder {
        public TextView tv_name;
        public ImageView iv_photo;
        public ProgressBar progressbar;
        public TextView tv_loading;
        public TextView tv_progress;
    }

    /**
     *
     * 移除上传成功的item
     * @param i
     *
     * 2016年7月28日
     *
     * ZhaoDongShao
     *
     */
    public void remove(int i) {
        // TODO Auto-generated method stub
        list.remove(i);
        notifyDataSetChanged();
    }
}

这个adapter很简单,就是个最普通不过的适配器,在适配器中小编用了基于Afinal的Xutils框架,不过目前该框架在6.0的系统上无法发挥效果,所以作者已经放弃维护,这里小编建议如果想继续使用Xutils的可以选择使用作者的新框架Xutil3,具体地址可以自行百度,如果想换个框架的话,小编推荐大家使用okhttp,这是一个非常好的框架,大家可以试试

上面的代码都是辅助代码,都是在实现功能的前提下所必需的,都不是很难,接下来我们一起看下核心的图片上传部分:

    /**
     * 上传的核心方法,可以直接调用
     * @param i 当前要上传的索引
     *
     * 2016年7月28日
     *
     * ZhaoDongShao
     *
     */
    protected void UploadPhoto(final int i) {
        // TODO Auto-generated method stub
        //设置item的下载状态为true
        lists.get(i).setDownload(true);
        //判断当前上传的item的索引值是否在当前显示的屏幕里,getFirstVisiblePosition()获取可见的第一条item的索引,getLastVisiblePosition()获取可见的最后一个索引
        if (i >= lv_upload.getFirstVisiblePosition() && i <= lv_upload.getLastVisiblePosition()) {

            int position = i - lv_upload.getFirstVisiblePosition();
            ProgressBar progressBar = (ProgressBar)lv_upload.getChildAt(position).findViewById(R.id.progressbar);
            TextView tv_loading = (TextView)lv_upload.getChildAt(position).findViewById(R.id.tv_loading);
            TextView tv_progress = (TextView)lv_upload.getChildAt(position).findViewById(R.id.tv_progress);
            tv_loading.setVisibility(View.GONE);
            tv_progress.setVisibility(View.VISIBLE);
            progressBar.setVisibility(View.VISIBLE);
        }

        if (httpUtils == null) {
            httpUtils = new HttpUtils();
        }
        //小编这里使用的Xutil的网络框架,大部分框架基本都是大同小异
        RequestParams rp = new RequestParams();
        rp.addBodyParameter("householderid", poorFamily.getHouseholderid());
        rp.addBodyParameter("file", new File(lists.get(i).getPath()));
        //设置网络访问超时时间
        httpUtils.configCurrentHttpCacheExpiry(1000 * 10);
        httpUtils.send(HttpRequest.HttpMethod.POST, URLs.IMAGE_UP_LOAD,
                rp, new RequestCallBack<String>() {
            //上传成功后会调用此方法
            @Override
            public void onSuccess(ResponseInfo<String> responseInfo) {

                FileRequestList list = FileRequestList.parseToT(responseInfo.result, FileRequestList.class);
                if (list != null) {

                    if (list.getSuccess()) {

                        if (adapter.getCount()>0) {
                            adapter.remove(i);
                            if (adapter.getCount() > 0) {
                                count_photo ++;
                                //上传完一张后,接着上传下一张
                                Message message = new Message();
                                message.what = 1;
                                Handler.sendMessage(message);
                            }else {
                                MyAdapter.mSelectedImage.clear();
                                showToast("成功上传" + count_photo + "张照片,重复" + count_photo_file +"张");
                            }
                        }

                    }else {

                        adapter.remove(i);
                        count_photo_file++;
                        Message message = new Message();
                        message.what = 1;
                        Handler.sendMessage(message);
                        showToast(list.getMsg());
                    }
                }
                System.out.println("上传成功");

            }

            @Override
            public void onFailure(HttpException error, String msg) {

                System.out.println("上传失败");

            }

            @Override
            public void onLoading(long total, long current, boolean isUploading) {

                int count = (int) ((current * 1.0 / total) * 100);
                lists.get(i).setDownload(true);
                lists.get(i).setProgress(count);
                //这里和上面的代码差不多,原理也相似,这里的i表示数据及显示位置
                if(i >= lv_upload.getFirstVisiblePosition() && i <= lv_upload.getLastVisiblePosition()) {
                    int positionInListView = i - lv_upload.getFirstVisiblePosition();
                    ProgressBar item = (ProgressBar) lv_upload.getChildAt(positionInListView)
                            .findViewById(R.id.progressbar);
                    TextView tv_progress = (TextView)lv_upload.getChildAt(positionInListView)
                            .findViewById(R.id.tv_progress);
                    tv_progress.setText(count + "%");
                    //设置进度条的进度
                    item.setProgress(count);
                }
                Log.i("上传 Progress>>>>>", "count=" + count + "--" + current + " / " + total);
            }
        });

首先来看看这个方法的参数:i表示在数据集中的位置,count表示进度,这个不难理解。接下来,我们通过更新list任务列表中对应条目的progress来保存一下现在的进度,但是,我们没有notify。接下来还是同样的逻辑,只不过,我们把控制ProgressBar显示的部分替换成了更新ProgressBar进度了。这样,我们就实现了,在不调用notifyDatasetChanged()的情况下来更新ListView的Item的目的。这样做有一个很明显的好处就是,每次,我们只更新一条item,其他的item我们并没有去更新,而notifyDatasetChanged的实现方式是,保存当前的位置,并更新所有的item,然后恢复位置。这样一比较,我们这种方式的优势就体现出来了。
有人可能还会有疑问,我们在滑动的时候怎么处理呢? 别忘了,我们在更新的前面都在list列表中更新了数据,所以在滑动的时候,我们交给Adapter.getView()去处理了。这样就很好理解了,所以用一个实体来保存上传的进度和状态,让我们在下一次滑动的时候能得到更好的更新ui。

因为我们这里要实现的是模仿QQ空间的图片上传效果,呢么就是每次都只是上传第一张图片,只有当第一张图片上传完毕后,再去调用上传,上传第二张图片,这里还用到了handler:

Handler Handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case 1:
                //当第一张图片上传完毕之后,接着上传第二张
                UploadPhoto(0);
                break;
            default:
                break;
            }
        };
    };

到这里ListView嵌套Progressbar就讲完了,其实也不是很复杂,主要就是要新建一个实体类来保存当前的进度。
效果图如下:
这里写图片描述
如果大家还有什么不懂的可以留言一起讨论,由于这是在公司项目中实现的,所就不附上demo了,以后有时间了。会及时附上demo

本篇博客纯手工敲出来的,希望大家都尊重小编的劳动成果,如需转载,请注明出处:http://blog.csdn.net/u010151514/article/details/52084190

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值