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>
















原文地址:https://www.cnblogs.com/mamamia/p/7827832.html