SwipeRefreshLayout+RecyclerView实现下拉刷新和上拉加载,并且添加了header和footer

在这里插入图片描述
大概页面是这样子,因为目前项目没上线,我也不能把图露出来。
my package上面的是固定的,是header,下面的package是获取到的信息需要展示的,也就是item
WIFI 和MEDIA 中间的两个圆圈是一个自定义view,一个圆圈加载的东西,通过获取数据并且画出来。

fragment_data_flow

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="620dp"
    android:layout_height="300dp"
    android:layout_marginLeft="250dp"
    android:layout_marginTop="70dp"
    android:orientation="vertical"
    tools:context=".mainPage.DataFlowFragment">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:orientation="horizontal">
        <ImageView
            android:layout_width="40dp"
            android:layout_height="35dp"
            android:layout_gravity="center_vertical"
            android:id="@+id/back_main"
            android:src="@drawable/ic_part_account_back"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:text="@string/data_flow"
            android:textSize="20dp"/>


        <TextView
            android:layout_width="100dp"
            android:layout_height="35dp"
            android:layout_gravity="center_vertical"
            android:id="@+id/buy"
            android:layout_marginLeft="350dp"
            android:text="@string/buy"
            android:textSize="20dp"
            android:gravity="center"
            android:background="@drawable/part_account_buy"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="10dp">

        <!-- 左边wifi的部分-->
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/wifi_fl"/>
        <!-- 右边media的部分-->
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:id="@+id/media_fl"/>
    </LinearLayout>

</LinearLayout>

这是DataFlowFragment的xml部分。两个frameLayout分别为两部分fragment

package com.xxx.personalcenter.mainPage;


import android.os.Build;
import android.view.View;
import android.widget.ImageView;

import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import com.xxx.personalcenter.R;

import com.xxx.personalcenter.base.BaseFragment;



public class DataFlowFragment extends BaseFragment implements View.OnClickListener{

    private static final String TAG = "DataFlowFragment";

    private ImageView backBtn;

    // 获取实例
    public static DataFlowFragment getInstance() {
        return DataFlowFragment.DataFlowHolder.get();
    }


    // 这个页面可以做成 如果流量页面加载失败,显示这个页面。可以点击按钮重新加载
    @Override
    protected int getLayoutId() {
        return R.layout.fragment_data_flow;
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void initView(View rootView) {

        backBtn=rootView.findViewById(R.id.back_main);
        // 分别加载两部分fragment
        replace(FlowMediaFragment.getInstance(),"mediaFragment",R.id.media_fl);
        replace(FlowWifiFragment.getInstance(),"wifiFragment",R.id.wifi_fl);

    }
    
    @Override
    protected void initListener(){
        backBtn.setOnClickListener(this);

    }

    @Override
    protected void loadData() {

    }



    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.back_main:
                FragmentManager manager= requireActivity().getSupportFragmentManager();
                manager.popBackStack("personal_center",0);
                break;
            default:
                break;
        }
    }
    private static class DataFlowHolder {
        private static final DataFlowFragment INSTANCE = new DataFlowFragment();

        public static DataFlowFragment get() {
            return INSTANCE;
        }
    }

    public void replace(Fragment fragment, String str,int page) {
        FragmentManager manager = requireActivity().getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.replace(page, fragment);
        transaction.addToBackStack(str);
        transaction.commit();
    }
}
package com.xxx.personalcenter.base;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import org.jetbrains.annotations.NotNull;

public abstract class BaseFragment  extends Fragment {



    @Nullable
    @org.jetbrains.annotations.Nullable
    @Override
    public View onCreateView(@NonNull @NotNull LayoutInflater inflater, @Nullable @org.jetbrains.annotations.Nullable ViewGroup container, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        View rootView=inflater.inflate(getLayoutId(),container,false);
        initView(rootView);
        initListener();
        loadData();
        return rootView;
    }

    protected abstract int getLayoutId();
    protected abstract void initView(View rootView);
    protected abstract void initListener();
    protected abstract void loadData();

}

这部分是我项目中BaseFragment部分。所有的Fragment都继承它

FlowMediaFragment 部分代码

package com.xxx.personalcenter.mainPage;

import android.os.Handler;
import android.util.Log;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import com.xxx.tools.https.ApiFactory;
import com.xxx.tools.https.Resp;
import com.xxx.personalcenter.R;
import com.xxx.personalcenter.adapter.FlowPackageAdapter;
import com.xxx.personalcenter.base.BaseFragment;
import com.xxx.personalcenter.unio.Constants;
import com.xxx.personalcenter.unio.FlowList;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

public class FlowMediaFragment extends BaseFragment implements SwipeRefreshLayout.OnRefreshListener{

    private static final String TAG = "FlowMediaFragment";

    private RecyclerView media_rv;
    private FlowPackageAdapter adapterMedia;

    // 下面这几个list是我处理获取得到的数据
    // 用于接受请求中返回的media和wifi集合
    private List<FlowList.FlowDetail> flowList;
    // 用于存放过滤之后的media package
    private List<FlowList.FlowDetail> mediaListFilter =new ArrayList<>();
    // 用于存放每次往adapter的list中设置的media package
    private List<FlowList.FlowDetail> mediaList=new ArrayList<>();

    private SwipeRefreshLayout swipeMedia;

    // media剩余长度
    private int mediaSurLength;
    private int mediaI=0;


    public static FlowMediaFragment getInstance() {
        return FlowMediaFragment.FlowMediaHolder.get();
    }

    @Override
    protected int getLayoutId() {
        return R.layout.fragment_media_flow;
    }

    @Override
    protected void initView(View rootView) {
        media_rv=rootView.findViewById(R.id.media_rv_view);
        swipeMedia =rootView.findViewById(R.id.media_sr_refresh);
        initAdapter();
    }

    @Override
    protected void initListener() {
        swipeMedia.setOnRefreshListener(this);
    }

    @Override
    protected void loadData() {
        getFlowList();
    }

    private void loadMore(){

        LinearLayoutManager manager=new LinearLayoutManager(getContext());
        media_rv.setLayoutManager(manager);
        adapterMedia=new FlowPackageAdapter(mediaList,getContext(),Constants.mediaPercentage,Constants.TYPE_MEDIA);
        media_rv.setItemAnimator(new DefaultItemAnimator());
        media_rv.setAdapter(adapterMedia);

        Log.d(TAG, "loadMore: media="+Constants.wifiPercentage);
        Log.d(TAG, "loadMore: mediaList="+ mediaListFilter.toString());
    }

    // load media
    private void loadMedia(){
        Log.d(TAG, "loadMedia:");
        if (mediaSurLength >2 ){
            for (int i=0;i<2;i++){
                mediaList.add(mediaListFilter.get(mediaI));
                mediaSurLength--;
                mediaI++;
                Log.d(TAG, "loadMedia: ");
            }
            Log.d(TAG, "loadMedia: mediaSurLength="+mediaSurLength);
            adapterMedia.hasMore(1);
        }else if (mediaSurLength >0){
            for (; mediaI< mediaListFilter.size(); mediaI++){
                mediaList.add(mediaListFilter.get(mediaI));
                mediaSurLength--;
                Log.d(TAG, "loadMedia: ");
            }
            adapterMedia.hasMore(1);
        }else {
            Log.d(TAG, "loadMedia: ");
            adapterMedia.hasMore(2);
        }
        adapterMedia.notifyDataSetChanged();
        adapterMedia.hasMore(3);
    }
    private void initAdapter(){
        loadMore();
        media_rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull @NotNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                /**
                 *  每次去通知adapter去更新数据的时候,先去开启加载动画,动画加载完之后再去通知关闭动画(loadMedia中的 hasMore(3) 表示关闭动画) 每次在加载数据的时候,要先开启加载动画,等数据加载进来之后在关闭加载动画
                 */
                adapterMedia.hasMore(1);
                adapterMedia.notifyDataSetChanged();
                if (newState==RecyclerView.SCROLL_STATE_IDLE){
                    //recyclerview滑动到底部,更新数据
                    //加载更多数据
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (mediaSurLength > 0) {
                                loadMedia();
                                Log.d(TAG, "onScrollStateChanged: "+"开始加载数据");
                            } else {
                                //没有数据了
                                Log.d(TAG, "run: ");
                                adapterMedia.hasMore(2);
                            }
                            adapterMedia.notifyDataSetChanged();
                            swipeMedia.setRefreshing(false);
                        }
                    },1000);
                }else if (newState==RecyclerView.INVALID_TYPE){
                    Log.d(TAG, "onScrollStateChanged: "+"media_INVALID_TYPE");
                    adapterMedia.hasMore(2);
                }
            }
        });
    }
    // 这个是我将获取的数据进行处理的方法,在此就不展示了
    private void filter(){//filter-
        
    }
    // 这是通过网络接口获取数据的方法,在此就不展示了
    private void getFlowList(){
        
    }

    @Override
    public void onRefresh() {
        swipeMedia.setRefreshing(true);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //清空数据
                adapterMedia.reData();
                mediaI=0;
                mediaSurLength =0;
                //重新获取数据
                getFlowList();
                //更新的数据
                //重新设置有更多数据
                adapterMedia.hasMore(1);
                adapterMedia.notifyDataSetChanged();
                //隐藏刷新效果  感觉这个隐藏刷新效果只能隐藏下拉刷新时,上面那个圈,自己定义的footer效果不能隐藏
                swipeMedia.setRefreshing(false);
                adapterMedia.hasMore(1);
            }
        }, 1000);
    }

    private static class FlowMediaHolder {
        private static final FlowMediaFragment INSTANCE = new FlowMediaFragment();

        public static FlowMediaFragment get() {
            return INSTANCE;
        }
    }

}

另一部分的wifi和media相同就不展示了。

FlowPackageAdapter

package com.xxx.personalcenter.adapter;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.xxx.personalcenter.R;
import com.xxx.personalcenter.unio.Constants;
import com.xxx.personalcenter.unio.FlowList;
import com.xxx.personalcenter.view.CirclePercentBar;

import org.jetbrains.annotations.NotNull;

import java.util.List;

public class FlowPackageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    // 用来区分时media还是wifi的类型
    public static final int DATA_TYPE_WIFI =2;
    public static final int DATA_TYPE_MEDIA =1;

    private List<FlowList.FlowDetail> objects;
    private static final String TAG = "FlowPackageAdapter";
    private int TYPE_HEADER=0;
    private int TYPE_ITEM = 1;//正常的Item
    private int TYPE_FOOT = 2;//尾部刷新

    // header 与 footer的个数
    private int mHeaderCount=1;
    private int mFooterCount=1;

    private float mPercentage;

    private Context mContext;
    private int state=1;

    private View mHeader;

    private  int dateType;


    public FlowPackageAdapter(List<FlowList.FlowDetail> objects, Context mContext,float percentage,int dateType) {
        this.objects = objects;
        this.mContext = mContext;
        this.mPercentage=percentage;
        this.dateType=dateType;
    }

    @Override
    public int getItemViewType(int position) {
        int dataItemCount=getCountItemCount();
        // 头部view
        if (mHeaderCount!=0 && position<mHeaderCount){
            return TYPE_HEADER;
        }else if (mFooterCount!=0 && position>=(mHeaderCount+dataItemCount)){
            return TYPE_FOOT;
        }else {
            return TYPE_ITEM;
        }
    }
    public int getCountItemCount(){
        return objects.size();
    }

    @NonNull
    @NotNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) {
        // 根据不同的view加载不同的布局
        if (viewType==TYPE_HEADER){
            return new FlowPackageAdapter.HeaderHolder(LayoutInflater.from(mContext).inflate(R.layout.wifi_header_view,parent,false));
        }else if (viewType==TYPE_ITEM){
            return new FlowPackageAdapter.ItemHolder(LayoutInflater.from(mContext).inflate(R.layout.flow_my_package_item,parent,false));
        }else {
            return new FlowPackageAdapter.FootHolder(LayoutInflater.from(mContext).inflate(R.layout.foot_boot, parent, false));
        }
    }

    @SuppressLint("SetTextI18n")
    @Override
    public void onBindViewHolder(@NonNull @NotNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof FlowPackageAdapter.ItemHolder) {
         ItemHolder _holder=(ItemHolder) holder;
          _holder.remain.setText(objects.get(position-mHeaderCount).getRemainValue()+"");
          _holder.all.setText(objects.get(position-mHeaderCount).getTotalValue()+"");
          _holder.packageName.setText(objects.get(position-mHeaderCount).getPackageName()+"");
        } else if (holder instanceof FlowPackageAdapter.FootHolder){
            Log.d(TAG, "onBindViewHolder: "+"footer");
            FootHolder _holder=(FootHolder)holder;
            switch (state){
                case 1:
                    _holder.tv_foot.setText("Loading。。");
                    _holder.tv_foot.setVisibility(View.VISIBLE);
                    _holder.pb_foot.setVisibility(View.VISIBLE);
                    break;
                case 2:
                    _holder.tv_foot.setText("No more");
                    _holder.tv_foot.setVisibility(View.VISIBLE);
                    _holder.pb_foot.setVisibility(View.GONE);
                    break;
                case 3:
                    if (objects.size()!=0){
                        _holder.tv_foot.setVisibility(View.GONE);
                    }else {
                        _holder.tv_foot.setText("No more");
                        _holder.tv_foot.setVisibility(View.VISIBLE);
                    }
                    _holder.pb_foot.setVisibility(View.GONE);
                    break;
                default:
                    break;
            }

        }else if (holder instanceof FlowPackageAdapter.HeaderHolder){
            HeaderHolder _holder=(HeaderHolder)holder;
            _holder.bar.setPercentData(mPercentage);
                if(this.dateType== DATA_TYPE_WIFI){//left
                    _holder.flowType.setText(R.string.media_inner);
                    _holder.flowDescription.setText(R.string.media_right);
                    _holder.company.setText(Constants.wifiCompany+"");
                    _holder.bar.setRemainFlow(Constants.wifiRemain);
                }else {//right
                    _holder.flowType.setText(R.string.wlan_inner);
                    _holder.flowDescription.setText(R.string.wlan_right);
                    _holder.company.setText(Constants.mediaCompany+"");
                    _holder.bar.setRemainFlow(Constants.mediaRemain);
                }
        }
    }

    @Override
    public int getItemCount() {
        return mHeaderCount+objects.size()+mFooterCount;
    }

    //item的holder
    static  class ItemHolder extends RecyclerView.ViewHolder {
        TextView packageName;
        TextView remain;
        TextView all;

        public ItemHolder(View itemView) {
            super(itemView);
            packageName=itemView.findViewById(R.id.packageName);
            remain=itemView.findViewById(R.id.remain);
            all=itemView.findViewById(R.id.all);
        }
    }
    static  class FootHolder extends RecyclerView.ViewHolder {
        private TextView tv_foot;
        private ProgressBar pb_foot;

        public FootHolder(View itemView) {
            super(itemView);
            tv_foot = itemView.findViewById(R.id.tv_foot);
            pb_foot = itemView.findViewById(R.id.pb_foot);
        }
    }
    static class HeaderHolder extends RecyclerView.ViewHolder {
        // 这个是自定义的控件
        private CirclePercentBar bar;
        private TextView flowType;
        private TextView flowDescription;

        private TextView company;
        public HeaderHolder(View itemView) {
            super(itemView);
            company=itemView.findViewById(R.id.company);
            bar=itemView.findViewById(R.id.circlePercentViewWifi);
            flowType=itemView.findViewById(R.id.flowType);
            flowDescription=itemView.findViewById(R.id.flowDescription);
        }
    }

    /**
     *  三种状态 1 还有更多数据
     *         2 无更多数据
     *         3 有更多数据,但是footer不需要再显示了
     * @param
     */
    public void hasMore(int state) {
        Log.d(TAG, "hasMore: ="+state);
        this.state = state;
    }

    //这里清空数据,避免下拉刷新后,还显示上拉加载的数据
    public void reData(){
        objects.clear();
    }


}

wifi_header_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="300dp"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    tools:context=".mainPage.DataFlowFragment">

        <LinearLayout
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:background="@drawable/home_page_round"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/media_inner"
                    android:textSize="15dp"
                    android:layout_gravity="center_vertical"
                    android:layout_marginLeft="20dp"
                    android:id="@+id/flowType"
                    />


                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/media_right"
                    android:textSize="10dp"
                    android:id="@+id/flowDescription"
                    android:layout_gravity="center_vertical"
                    android:layout_marginLeft="10px"/>
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:orientation="vertical">

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

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal"
                        android:layout_marginLeft="110dp"
                        android:layout_marginTop="38dp"
                        >

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:id="@+id/available_flow"
                            android:text="@string/available_flow"
                            android:textSize="10dp"/>
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:id="@+id/company"
                            android:text="(GB)"
                            android:textSize="12dp"
                            />


                    </LinearLayout>

                    <com.xxx.personalcenter.view.CirclePercentBar
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_horizontal"
                        app:arcColor="#CCCCCC"
                        app:arcWidth="14dp"
                        app:centerTextColor="#E8E8E7"
                        app:centerTextSize="25sp"
                        app:circleRadius="65dp"
                        app:arcStartColor="#6A6969"
                        android:id="@+id/circlePercentViewWifi"/>


                </FrameLayout>

            </LinearLayout>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/my_package"
                android:layout_marginLeft="20dp"
                android:layout_marginBottom="5dp"/>

        </LinearLayout>
</LinearLayout>

footer

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="280dp"
    android:layout_height="40dp"
    android:gravity="center"
    android:orientation="horizontal"
    android:background="@drawable/part_account_item_round">

    <ProgressBar
        android:layout_width="30dp"
        android:layout_height="45dp"
        android:id="@+id/pb_foot"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/tv_foot"
        android:visibility="visible"
        android:textSize="10dp"/>
</LinearLayout>

item

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="280dp"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:layout_marginLeft="8dp"
    android:background="@drawable/part_account_item_round">

    <LinearLayout
        android:layout_width="280dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="5dp"
        android:id="@+id/tipsTop"
        android:background="@drawable/part_account_mypackage">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/data_flow_monthly"
            android:layout_gravity="center_vertical"
            android:id="@+id/packageName"
            android:layout_marginLeft="8dp"
            android:textSize="12dp"/>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="80dp"
            android:layout_gravity="center_vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/remain"
                android:text="0.0"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="/"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/all"
                android:text="8.0 GB"/>

        </LinearLayout>

    </LinearLayout>

</LinearLayout>

自定义控件内容

package com.xxx.personalcenter.view;

import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;

import com.xxx.personalcenter.R;
import com.xxx.personalcenter.util.DensityUtils;

import java.text.DecimalFormat;

import static android.content.ContentValues.TAG;

public class CirclePercentBar extends View {


    private int mArcColor;
    private int mArcWidth;
    private int mCenterTextColor;
    private int mCenterTextSize;
    private int mCenterTextTopSize;
    private int mCircleRadius;
    private int mArcStarColor;
    private float mRemainFlow;

    private Paint startCirclePaint;
    private Paint arcCirclePaint;
    private Paint arcPaint;
    private Paint centerTextPaint;
    private Paint centerTextTopPaint;
    private RectF arcRectF;
    private Rect textBoundRect;


    private float mCurData=0.0f;

    public CirclePercentBar(Context context) {
        this(context,null);
    }

    public CirclePercentBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);


    }
    public CirclePercentBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        Log.d(TAG, "CirclePercentBar:");

        TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.CirclePercentBar,defStyleAttr,0);
        mArcColor=typedArray.getColor(R.styleable.CirclePercentBar_arcColor,0xff0000);
        mArcWidth=typedArray.getDimensionPixelSize(R.styleable.CirclePercentBar_arcWidth, DensityUtils.dp2px(context,20));
        mCenterTextColor=typedArray.getColor(R.styleable.CirclePercentBar_arcColor,0x0000ff);
        Log.d(TAG, "mArcWidth: "+mArcWidth);
        mCenterTextSize=typedArray.getDimensionPixelSize(R.styleable.CirclePercentBar_centerTextSize,DensityUtils.dp2px(context,20));
        mCenterTextTopSize=typedArray.getDimensionPixelSize(R.styleable.CirclePercentBar_centerTextTopSize,DensityUtils.dp2px(context,10));
        mCircleRadius=typedArray.getDimensionPixelSize(R.styleable.CirclePercentBar_circleRadius,DensityUtils.dp2px(context,100));
        mArcStarColor=typedArray.getColor(R.styleable.CirclePercentBar_arcStartColor, ContextCompat.getColor(getContext(),R.color.colorStart));
        typedArray.recycle();
        initPaint();
    }



    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureView(widthMeasureSpec),measureView(heightMeasureSpec));
    }

    private int measureView(int measureSpec){
        int result;
        int specMod=MeasureSpec.getMode(measureSpec);
        int specSize=MeasureSpec.getSize(measureSpec);
        if (specMod==MeasureSpec.EXACTLY){
            result=specSize;
        }else {
            result=mCircleRadius*2;
            if (specMod==MeasureSpec.AT_MOST){
                result=Math.min(result,specSize);
            }
        }
        return result;
    }
     
     // 设置圆环的填充
    public void setPercentData(float data){
        // 处理浮点型数据。还有 ofInt..等等
        ValueAnimator valueAnimator=ValueAnimator.ofFloat(mCurData,data);
        valueAnimator.setDuration((long)(Math.abs(mCurData-data)*20));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                // 这个value就是前面传过来的数据,在前面就应该换算成百分比数传过来。
                float value=(float)valueAnimator.getAnimatedValue();
                mCurData=(float) value;
                invalidate();
            }
        });
        valueAnimator.start();
    }

	// 设置圆环里字体的大小
    public void setRemainFlow(float remain){
        ValueAnimator valueAnimator=ValueAnimator.ofFloat(mRemainFlow,remain);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mRemainFlow= (float)valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.start();
    }

    private void initPaint(){
        Log.d(TAG, "initPaint:");

        // 未填充状态的背景圆环
        arcCirclePaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        arcCirclePaint.setStyle(Paint.Style.STROKE);
        arcCirclePaint.setStrokeWidth(mArcWidth);
        arcCirclePaint.setColor(ContextCompat.getColor(getContext(),R.color.circlePaint));
        arcCirclePaint.setAlpha(30);
        arcCirclePaint.setStrokeCap(Paint.Cap.BUTT);

        // 百分比占据的圆弧
        arcPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        // 只设置了描边
        arcPaint.setStyle(Paint.Style.STROKE);
        arcPaint.setStrokeWidth(mArcWidth);
        arcPaint.setColor(mArcColor);
        arcPaint.setStrokeCap(Paint.Cap.BUTT);

        // 圆环中的百分比文字
        centerTextPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        centerTextPaint.setStyle(Paint.Style.FILL);
        centerTextPaint.setColor(mCenterTextColor);
        centerTextPaint.setTextSize(mCenterTextSize);

        // 圆环中百分比文字上面的文字
        centerTextTopPaint=new Paint();
        centerTextTopPaint.setStyle(Paint.Style.STROKE);
        centerTextTopPaint.setColor(mCenterTextColor);
        centerTextTopPaint.setTextSize(mCenterTextTopSize);

        // 圆弧的外接矩形
        arcRectF=new RectF();

        // 文字的边界矩形
        textBoundRect=new Rect();

    }
    @Override
    protected void onDraw(Canvas canvas) {
        Log.d(TAG, "onDraw: onDraw");
        canvas.rotate(-90,getWidth()/2,getHeight()/2);
        arcRectF.set(getWidth()/2-mCircleRadius+mArcWidth/2,getHeight()/2-mCircleRadius+mArcWidth/2,
                getWidth()/2+mCircleRadius-mArcWidth/2,getHeight()/2+mCircleRadius-mArcWidth/2);
        canvas.drawArc(arcRectF,0,360,false,arcCirclePaint);

        // SweepGradient 扫描渐变
        arcPaint.setShader(new SweepGradient(getWidth()/2,getHeight()/2,mArcStarColor,mArcStarColor));
        // 绘制圆圈中间的文字
        canvas.drawArc(arcRectF,0,360*mCurData/100,false,arcPaint);

        canvas.rotate(90,getWidth()/2,getHeight()/2);
//        canvas.drawCircle(getWidth()/2,getHeight()/2-mCircleRadius+mArcWidth/2,mArcWidth/2,startCirclePaint);

        // 圆圈中间显示的文字
        @SuppressLint("DrawAllocation") DecimalFormat format=new DecimalFormat("##0.00");
        String data=format.format(mRemainFlow);
        centerTextPaint.getTextBounds(data,0,data.length(),textBoundRect);
        Log.d(TAG, "onDraw: getHeight="+getHeight());
        Log.d(TAG, "onDraw: getWeight="+getWidth());
        Log.d(TAG, "onDraw: gextBoundRect.height="+textBoundRect.height());
        canvas.drawText(data,getWidth()/2-textBoundRect.width()/2,getHeight()/2+textBoundRect.height()/2,centerTextPaint);
    }

}

自定义圆环中定义的一些属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CirclePercentBar">
        <attr name="arcColor" format="color"/>
        <attr name="arcWidth" format="dimension"/>
        <attr name="centerTextColor" format="color"/>
        <attr name="centerTextSize" format="dimension"/>
        <attr name="centerTextTopSize" format="dimension"/>
        <attr name="circleRadius" format="dimension"/>
        <attr name="arcStartColor" format="color"/>
    </declare-styleable>
</resources>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值