zoukankan      html  css  js  c++  java
  • ListView ,recycleView列表带进度条

    实现上图功能有两种思路。

    一:普通做法,更新item的数据,不停调用notifydatachange ;

    二:各管自家刷新。

          一个下载对应一个下载线程。线程持有对应item在Listview中的位置。当该线程所对应的item可见时,获得该Item的progressbar更新。

    第二种方式相对省资源效率更高。

    一步步来解决关键问题:

    1.进度条实现

    不熟悉进度条progressbar的样式定义,可以翻系统的源码。

    水平样式:

    <pre name="code" class="java">    
    <style name="Widget.ProgressBar.Horizontal"> <item name="android:indeterminateOnly">false</item> <item name="android:progressDrawable">@android:drawable/progress_horizontal</item> <item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal</item> <item name="android:minHeight">20dip</item> <item name="android:maxHeight">20dip</item> <item name="android:mirrorForRtl">true</item> </style>

    关键是:

    <style name="Widget.ProgressBar.Horizontal">和android:indeterminateDrawable

     制一个Item布局

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="86dp"
        android:paddingTop="15dp"
        tools:context="com.loopbanner.DiscoveryFragment">
    
        <ImageView
            android:id="@+id/iv_soft_icon"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="13dp"
            android:scaleType="fitXY"
            android:src="@mipmap/ic_launcher_round" />
    
        <TextView
            android:layout_toLeftOf="@+id/rl_pro"
            android:id="@+id/tv_soft_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="10dp"
            android:layout_toRightOf="@+id/iv_soft_icon"
            android:maxLines="1"
            android:text="TextView"
            android:textColor="#333333" />
    
        <TextView
            android:layout_toLeftOf="@+id/rl_pro"
            android:layout_toRightOf="@+id/iv_soft_icon"
            android:id="@+id/tv_introduce"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/tv_soft_name"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="10dp"
            android:maxLines="1"
            android:text="TextView"
            android:textColor="#999999" />
    
        <RelativeLayout
            android:id="@+id/rl_pro"
            android:layout_width="60dp"
            android:layout_height="25dp"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:layout_marginEnd="12dp"
            android:gravity="center">
    
            <ProgressBar
                android:id="@+id/progressbar"
                style="@android:style/Widget.ProgressBar.Horizontal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:indeterminateOnly="false"
                android:max="100"
                android:minHeight="25dp"
                android:progress="0"
                android:progressDrawable="@drawable/progress_bg_list" />
    
            <TextView
                android:id="@+id/tv_donwload"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="下载"
                android:textColor="#F88C08" />
        </RelativeLayout>
    
        <View
            android:id="@+id/view"
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:layout_alignParentBottom="true"
            android:layout_marginLeft="83dp"
            android:background="#999999">
    
        </View>
    </RelativeLayout>

    自定义

    android:indeterminateDrawable
    <?xml version="1.0" encoding="utf-8"?>
    
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item android:id="@android:id/background">
            <shape>
                <corners android:radius="12.5dip" />
                <solid android:color="#fff" />
                <stroke
                    android:width="1dp"
                    android:color="#F88C08" />
            </shape>
        </item>
    
        <item android:id="@android:id/secondaryProgress">
            <clip>
                <shape>
                    <corners android:radius="12.5dip" />
                    <gradient
                        android:angle="270"
                        android:centerColor="#EE5C42"
                        android:centerY="0.75"
                        android:endColor="#EE5C42"
                        android:startColor="#EE5C42" />
                </shape>
            </clip>
        </item>
    
        <item android:id="@android:id/progress">
            <clip>
                <shape>
                    <corners android:radius="12.5dip" />
                    <solid android:color="#FEE2CD" />
                    <stroke
                        android:width="1dp"
                        android:color="#F88C08" />
                </shape>
            </clip>
        </item>
    
    </layer-list>

    效果如下:

    按一种思路,下载只针对data数据操作。adapter要不断刷新。这个原理比较简单,不再写了。
    第二种思路的关键是,下载线程去刷新progressbar,关键点是找是当前是否可见的item并刷新。
    看一下关键代码:
    找到当前可见item是listView现有api,这里面出于设计模式考虑。activity不要跟下载线程有交互,减少耦合。那么数据作都与adapter去交互。所以使用以下方法获取ListView:

    int firstItem = mAdapter.getListView().getFirstVisiblePosition();
    int lastItem = mAdapter.getListView().getLastVisiblePosition();

    下一步如何生成持有位置信息的下载类。通常方法都是要adapter 的getview方法里去设置tag.
    vh.tvDonwload.setOnClickListener(onClickListener);
    vh.tvDonwload.setTag(R.id.progressbar, vh.progressbar);
    vh.tvDonwload.setTag(R.id.tag_progress_bar, vh.progressbar);
    vh.tvDonwload.setTag(R.id.tag_positon, position);
    vh.progressbar.setTag(R.id.tag_url);

    如何设置多个tag请自行baidu,给一个唯一id和一下object ;

    可以如下去做:
    <resources>
        <string name="hello_blank_fragment">Hello blank fragment</string>
        <item name="tag_positon" type="id">1</item>
        <item name="tag_progress_bar" type="id">2</item>
        <item name="tag_url" type="id">3</item>
    </resources>



    在点击时开启下载工作。
     public View.OnClickListener onClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v instanceof TextView) {
                    int pos = (int) v.getTag(R.id.tag_positon);
                    DiscoveryModel item = (DiscoveryModel) getItem(pos);
                    if (item.getStatus() == DiscoveryModel.NORMAL) {
                        ((TextView) v).setText("0%");
                        new FileDownLoaderTask(DiscoveryAdapter.this, pos);
                        item.setStatus(DiscoveryModel.DOWNLOADING);
                    } else if (item.getStatus() == DiscoveryModel.DOWNLOADING) {
                        item.setStatus(DiscoveryModel.PAUSE);
                    }
                }
            }
        };

    最后是如何更新

    看代码:

    //如果本下载线程所带的item的位置在当前listview中可见
    if (((DiscoveryModel) mAdapter.getItem(mPosition)).getStatus() == DiscoveryModel.DOWNLOADING && firstItem <= mPosition && mPosition <= lastItem) {
       //在listview中找到该item
        for (int i = 0; i < mAdapter.getListView().getChildCount(); i++) {
         //通过比对tag的位置 
            if ((int) (mAdapter.getListView().getChildAt(i).findViewById(R.id.tv_donwload).getTag(R.id.tag_positon)) == mPosition) {
            //找到ProgressBar 去更新;
            ProgressBar progressBar = (ProgressBar) mAdapter.getListView().getChildAt(i).findViewById(R.id.progressbar);
                progressBar.setProgress(process);
                TextView tv_donwload = (TextView) mAdapter.getListView().getChildAt(i)
                        .findViewById(R.id.tv_donwload);
                progressBar.setProgress(process);
                tv_donwload.setText(process + "%");
            }
        }
    }



     帖上所有代码

    MainActivity

    package com.loopbanner;
    
    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    
    public class MainActivity extends FragmentActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction ft = fragmentManager.beginTransaction();
            ft.add(R.id.root, new DiscoveryFragment());
            ft.commit();
        }
    }

    fragment

    package com.loopbanner;
    
    
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ListView;
    import android.widget.Toast;
    
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    /**
     * A simple {@link Fragment} subclass.
     */
    public class DiscoveryFragment extends Fragment {
    
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_discovery, container, false);
            init(rootView);
            return rootView;
        }
    
        ListView mListView;
        DiscoveryAdapter mAdapter;
        List<Object> modelList;
    
        private void init(View rootView) {
            mListView = (ListView) rootView.findViewById(R.id.lv_discovery);
            modelList = new ArrayList<>();
            mAdapter = new DiscoveryAdapter(getActivity(), modelList);
            mListView.setAdapter(mAdapter);
            getData();
        }
    
        private void getData() {
            GetDiscoveryDataTask gddt = new GetDiscoveryDataTask() {
                @Override
                public void onResult(String resMsg, int code) {
                    if (resMsg != null && resMsg.length() > 0) {
                        parseData(resMsg);
                    } else {
                        Toast.makeText(getActivity(), "未获取到数据!", Toast.LENGTH_SHORT).show();
                    }
                }
            };
            gddt.request();
        }
    
    
        public void parseData(String string) {
            try {
                JSONObject jsonObject = new JSONObject(string);
                if (jsonObject != null) {
                    JSONArray jsonArray = jsonObject.optJSONArray("apps");
                    if (jsonArray != null && jsonArray.length() > 0) {
                        for (int i = 0; i < jsonArray.length(); i++) {
                            DiscoveryModel dm = new DiscoveryModel();
                            JSONObject app = (JSONObject) jsonArray.get(i);
                            dm.setSoftId(app.optString("softId"));
                            dm.setSoftBrief(app.optString("softBrief"));
                            dm.setSoftDown(app.optString("softDown"));
                            dm.setSoftLogo(app.optString("softLogo"));
                            dm.setSoftName(app.optString("softName"));
                            modelList.add(dm);
                        }
                        mAdapter.notifyDataSetChanged();
                    }
                }
    
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    
    
    }

    adpater

    package com.loopbanner;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.ImageView;
    import android.widget.ListView;
    import android.widget.ProgressBar;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    
    import com.bumptech.glide.Glide;
    
    import java.util.List;
    
    public class DiscoveryAdapter extends ArrayAdapter<Object> {
        private static class ViewHolder {
            public final RelativeLayout rootView;
            public final ImageView ivSoftIcon;
            public final TextView tvSoftName;
            public final TextView tvIntroduce;
            public final ProgressBar progressbar;
            public final TextView tvDonwload;
            public final View view;
    
            private ViewHolder(RelativeLayout rootView, ImageView ivSoftIcon, TextView tvSoftName, TextView tvIntroduce, ProgressBar progressbar, TextView tvDonwload, View view) {
                this.rootView = rootView;
                this.ivSoftIcon = ivSoftIcon;
                this.tvSoftName = tvSoftName;
                this.tvIntroduce = tvIntroduce;
                this.progressbar = progressbar;
                this.tvDonwload = tvDonwload;
                this.view = view;
            }
    
            public static ViewHolder create(RelativeLayout rootView) {
                ImageView ivSoftIcon = (ImageView) rootView.findViewById(R.id.iv_soft_icon);
                TextView tvSoftName = (TextView) rootView.findViewById(R.id.tv_soft_name);
                TextView tvIntroduce = (TextView) rootView.findViewById(R.id.tv_introduce);
                ProgressBar progressbar = (ProgressBar) rootView.findViewById(R.id.progressbar);
                TextView tvDonwload = (TextView) rootView.findViewById(R.id.tv_donwload);
                View view = (View) rootView.findViewById(R.id.view);
                return new ViewHolder(rootView, ivSoftIcon, tvSoftName, tvIntroduce, progressbar, tvDonwload, view);
            }
        }
    
        GlideRoundTransform glideRoundTransform;
        ListView mListView;
    
        public ListView getListView() {
            return mListView;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            mListView = (ListView) parent;
            final ViewHolder vh;
            if (convertView == null) {
                View view = mInflater.inflate(R.layout.fragment_discovery_item, parent, false);
                vh = ViewHolder.create((RelativeLayout) view);
                view.setTag(vh);
            } else {
                vh = (ViewHolder) convertView.getTag();
            }
    
    
            DiscoveryModel item = (DiscoveryModel) getItem(position);
            vh.tvSoftName.setText(item.getSoftName());
            vh.tvIntroduce.setText(item.getSoftBrief());
            Glide.with(getContext()).load(item.getSoftLogo()).transform(this.glideRoundTransform).into(vh.ivSoftIcon);
            vh.progressbar.setProgress(item.getCompletePercent());
            switch (item.getStatus()) {
                case DiscoveryModel.DOWNLOADING:
                    vh.tvDonwload.setText(item.getCompletePercent() + "%");
                    break;
                case DiscoveryModel.NORMAL:
                    vh.tvDonwload.setText("下载");
                    break;
                case DiscoveryModel.PAUSE:
                    vh.tvDonwload.setText("暂停");
                    break;
            }
    
    
            vh.tvDonwload.setOnClickListener(onClickListener);
            vh.tvDonwload.setTag(R.id.progressbar, vh.progressbar);
            vh.tvDonwload.setTag(R.id.tag_progress_bar, vh.progressbar);
            vh.tvDonwload.setTag(R.id.tag_positon, position);
            vh.progressbar.setTag(R.id.tag_url);
    
            return vh.rootView;
        }
    
        private LayoutInflater mInflater;
    
        // Constructors
        public DiscoveryAdapter(Context context, List<Object> objects) {
            super(context, 0, objects);
            this.mInflater = LayoutInflater.from(context);
            glideRoundTransform = new GlideRoundTransform(getContext());
        }
    
    
        public DiscoveryAdapter(Context context, Object[] objects) {
            super(context, 0, objects);
            this.mInflater = LayoutInflater.from(context);
            glideRoundTransform = new GlideRoundTransform(getContext());
        }
    
    
        public View.OnClickListener onClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v instanceof TextView) {
                    int pos = (int) v.getTag(R.id.tag_positon);
                    DiscoveryModel item = (DiscoveryModel) getItem(pos);
                    if (item.getStatus() == DiscoveryModel.NORMAL) {
                        ((TextView) v).setText("0%");
                        new FileDownLoaderTask(DiscoveryAdapter.this, pos);
                        item.setStatus(DiscoveryModel.DOWNLOADING);
                    } else if (item.getStatus() == DiscoveryModel.DOWNLOADING) {
                        item.setStatus(DiscoveryModel.PAUSE);
                    }
                }
            }
        };
    }

    laoder模拟

    package com.loopbanner;
    
    import android.os.Handler;
    import android.os.Message;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    /**
     * 本类负责,下载数据,并更新UI
     * 更新逻辑为:当前类保存apapter引用。获取数据后,如果本类所属的item是可见的,
     * 则更新progressbar
     */
    
    public class FileDownLoaderTask {
        private String mUrl;
        private int process = 0;
        private DiscoveryAdapter mAdapter;
        private int mPosition;
    
        public FileDownLoaderTask(DiscoveryAdapter adapter, int position) {
            mAdapter = adapter;
            mUrl = ((DiscoveryModel) adapter.getItem(position)).getSoftDown();
            mHandler.sendEmptyMessageDelayed(1, 500);
            mPosition = position;
        }
    
    
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                process += 1;
                ((DiscoveryModel) mAdapter.getItem(mPosition)).setCompletePercent(process);
                int firstItem = mAdapter.getListView().getFirstVisiblePosition();
                int lastItem = mAdapter.getListView().getLastVisiblePosition();
                if (((DiscoveryModel) mAdapter.getItem(mPosition)).getStatus() == DiscoveryModel.DOWNLOADING && firstItem <= mPosition && mPosition <= lastItem) {
                    for (int i = 0; i < mAdapter.getListView().getChildCount(); i++) {
                        if ((int) (mAdapter.getListView().getChildAt(i).findViewById(R.id.tv_donwload).getTag(R.id.tag_positon)) == mPosition) {
                            ProgressBar progressBar = (ProgressBar) mAdapter.getListView().getChildAt(i)
                                    .findViewById(R.id.progressbar);
                            progressBar.setProgress(process);
                            TextView tv_donwload = (TextView) mAdapter.getListView().getChildAt(i)
                                    .findViewById(R.id.tv_donwload);
                            progressBar.setProgress(process);
                            tv_donwload.setText(process + "%");
                        }
                    }
                }
                if (process != 100) {
                    mHandler.sendEmptyMessageDelayed(1, 500);
                }
            }
        };
    }

    资源

    <?xml version="1.0" encoding="utf-8"?>
    
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item android:id="@android:id/background">
            <shape>
                <corners android:radius="12.5dip" />
                <solid android:color="#fff" />
                <stroke
                    android:width="1dp"
                    android:color="#F88C08" />
            </shape>
        </item>
    
        <item android:id="@android:id/secondaryProgress">
            <clip>
                <shape>
                    <corners android:radius="12.5dip" />
                    <gradient
                        android:angle="270"
                        android:centerColor="#EE5C42"
                        android:centerY="0.75"
                        android:endColor="#EE5C42"
                        android:startColor="#EE5C42" />
                </shape>
            </clip>
        </item>
    
        <item android:id="@android:id/progress">
            <clip>
                <shape>
                    <corners android:radius="12.5dip" />
                    <solid android:color="#FEE2CD" />
                    <stroke
                        android:width="1dp"
                        android:color="#F88C08" />
                </shape>
            </clip>
        </item>
    
    </layer-list>
















  • 相关阅读:
    通过队列实现进程间的通信(使用阻塞方式调用func函数)
    Scrapy 项目:QuotesBot
    数据分析_找数据参考网站
    Matplotlib 图表绘制工具学习笔记
    Python算法_斐波那契数列(10)
    Python算法_排序数组(09)
    Python数据结构与算法_反转字符串(08)
    Python算法_爬楼梯(08)
    Python数据结构与算法_搜索插入位置(07)
    Python数据结构与算法_删除排序数组中的重复项(06)
  • 原文地址:https://www.cnblogs.com/mamamia/p/7827832.html
Copyright © 2011-2022 走看看