adapter|okHttp网络请求2——MVP

adapter包
package adapter;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.sax.StartElementListener;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.example.dell.zhoukao3.Main2Activity;
import com.example.dell.zhoukao3.Main3Activity;
import com.example.dell.zhoukao3.R;

import java.util.List;

import bean.Shop;

/**
* Created by DELL on 2017/10/21.
*/

public class MyAdapter extends RecyclerView.Adapter {

private Activity context;
private List data;
private final int atype=0;
private final int btype=1;
private final int ctype=2;

public MyAdapter(Activity context, List data) {
this.context = context;
this.data = https://www.it610.com/article/data;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//View view = View.inflate(context, R.layout.rv_item, null);
View view=null;
RecyclerView.ViewHolder holder=null;
switch (viewType)
{
case atype:

view = View.inflate(context, R.layout.rv_item1, null);
holder=new ViewHolder1(view);

break;


case btype:
view = View.inflate(context, R.layout.rv_item2, null);
holder=new ViewHolder2(view);
break;


case ctype:
view = View.inflate(context, R.layout.rv_item3, null);
holder=new ViewHolder3(view);
break;
}
return holder;
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {

switch (getItemViewType(position))
{
case atype:
ViewHolder1 holder1= (ViewHolder1) holder;
holder1.tv_name.setText(data.get(position).title);
holder1.tv_price.setText(data.get(position).price+"");
String images = data.get(position).images;
String[] img = images.split("\\|");
Glide.with(context).load(img[0]).into(holder1.iv);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

Intent intent=new Intent(context, Main3Activity.class);
intent.putExtra("title",data.get(position).title);
context.startActivity(intent);
}
});
break;
case btype:
ViewHolder2 holder2= (ViewHolder2) holder;
holder2.tv_name.setText(data.get(position).title);
holder2.tv_price.setText(data.get(position).price+"");
String images1 = data.get(position).images;
String[] img1 = images1.split("\\|");
Glide.with(context).load(img1[0]).into(holder2.iv);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(context, Main3Activity.class);
intent.putExtra("title",data.get(position).title);
context.startActivity(intent);
}
});

break;
case ctype:
ViewHolder3 holder3= (ViewHolder3) holder;
holder3.tv_name.setText(data.get(position).title);
holder3.tv_price.setText(data.get(position).price+"");
String images2 = data.get(position).images;
String[] img2 = images2.split("\\|");
Glide.with(context).load(img2[0]).into(holder3.iv);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(context, Main3Activity.class);
intent.putExtra("title",data.get(position).title);
context.startActivity(intent);
}
});
break;
}




}
@Override
public int getItemCount() {
return data.size();
}

public class ViewHolder1 extends RecyclerView.ViewHolder{

private final TextView tv_name;
private final TextView tv_price;
private final ImageView iv;

public ViewHolder1(View itemView) {
super(itemView);
tv_name = itemView.findViewById(R.id.tv_name);
tv_price = itemView.findViewById(R.id.tv_price);
iv = itemView.findViewById(R.id.iv);
}
}
public class ViewHolder2 extends RecyclerView.ViewHolder{

private final TextView tv_name;
private final TextView tv_price;
private final ImageView iv;

public ViewHolder2(View itemView) {
super(itemView);
tv_name = itemView.findViewById(R.id.tv_name);
tv_price = itemView.findViewById(R.id.tv_price);
iv = itemView.findViewById(R.id.iv);
}
}

public class ViewHolder3 extends RecyclerView.ViewHolder{

private final TextView tv_name;
private final TextView tv_price;
private final ImageView iv;

public ViewHolder3(View itemView) {
super(itemView);
tv_name = itemView.findViewById(R.id.tv_name);
tv_price = itemView.findViewById(R.id.tv_price);
iv = itemView.findViewById(R.id.iv);
}
}

@Override
public int getItemViewType(int position) {
if(data.get(position).itemtype==0)
{
return atype;
}
else if(data.get(position).itemtype==1)
{
return btype;
}
else
{
return ctype;
}
}
}



Bean类
bean
package bean;

import java.util.List;

/**
* Created by DELL on 2017/10/21.
*/

public class Shop {

public String msg;
public String code;
public String page;
public List data;

public static class DataBean {

public double bargainPrice;
public String createtime;
public String detailUrl;
public String images;
public int itemtype;
public int pid;
public double price;
public int pscid;
public int salenum;
public int sellerid;
public String subhead;
public String title;
}
}


Main包
MainActivity
package com.example.dell.zhoukao3;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AnimationSet;
import android.widget.ImageView;
import android.widget.Toast;

import view.CountDownProgress;

public class MainActivity extends AppCompatActivity {

private ImageView iv;
private CountDownProgress countDownProgress;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}

private void initData() {
ObjectAnimator animator=ObjectAnimator.ofFloat(iv,"translationY",0f,250f);
ObjectAnimator animator1=ObjectAnimator.ofFloat(iv,"scaleX",1,2);
ObjectAnimator animator2=ObjectAnimator.ofFloat(iv,"scaleX",2,1);
AnimatorSet set=new AnimatorSet();
set.play(animator1).before(animator2).after(animator);
set.setDuration(3000);
set.start();
}

private void initView() {
iv = (ImageView) findViewById(R.id.iv);
countDownProgress = (CountDownProgress) findViewById(R.id.countdownProgress);
countDownProgress.setCountdownTime(10*1000);

countDownProgress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
countDownProgress.startCountDownTime(new CountDownProgress.OnCountdownFinishListener() {
@Override
public void countdownFinished() {
//Toast.makeText(MainActivity.this, "倒计时结束了--->该UI处理界面逻辑了", Toast.LENGTH_LONG).show();
Intent intent=new Intent(MainActivity.this,Main2Activity.class);
startActivity(intent);
}
});
/*Message message = Message.obtain();
message.what = HANDLER_MESSAGE;
handler.sendMessage(message); */
}
});
}
}

Main2Activity
package com.example.dell.zhoukao3;

import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import com.jcodecraeer.xrecyclerview.XRecyclerView;

import java.io.IOException;
import java.util.List;

import adapter.MyAdapter;
import bean.Shop;
import okhttp3.Call;
import presenter.ShopPresenter;
import view.ShopView;

public class Main2Activity extends AppCompatActivity implements ShopView {
private String s;
private SwipeRefreshLayout swiperefreshlayout;
private XRecyclerView recycler;
private ShopPresenter presenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
// System.out.println(s.equals("any string"));
initView();
initData();

}

private void initData() {
presenter = new ShopPresenter(this);


}

private void initView() {
recycler = (XRecyclerView) findViewById(R.id.rv);
recycler.setLoadingMoreEnabled(true);
recycler.setPullRefreshEnabled(true);

}

@Override
public void onShopSuccess(final List data) {
System.out.println(data.size()+"^^^^^^^^^^^^");
if(this!=null)
{
runOnUiThread(new Runnable() {
@Override
public void run() {

LinearLayoutManager linearLayoutManager=new LinearLayoutManager(Main2Activity.this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);

recycler.setLayoutManager(linearLayoutManager);
MyAdapter adapter=new MyAdapter(Main2Activity.this,data);
recycler.setAdapter(adapter);

recycler.setLoadingListener(new XRecyclerView.LoadingListener() {
@Override
public void onRefresh() {
presenter.requestShop(1);
recycler.refreshComplete();
}

@Override
public void onLoadMore() {
presenter.requestShop(2);
recycler.loadMoreComplete();

}
});


}
});
}
}

@Override
public void onShopFailure(String msg) {

}

@Override
public void onFailure(Call call, IOException e) {

}

@Override
protected void onResume() {
super.onResume();
presenter.requestShop(1);
}
}

MyApp
package com.example.dell.zhoukao3;

import android.app.Application;

import utils.CrashHandler;

/**
* Created by DELL on 2017/10/21.
*/

public class MyApp extends Application{
@Override
public void onCreate() {
super.onCreate();
/*CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(getApplicationContext()); */
}
}


api类
API
package common;

/**
* Created by DELL on 2017/10/21.
*/

public class Api {

public staticfinal String URL="http://120.27.23.105/product/getProducts?pscid=1";
}



拦截器
Interceptor

package lanjieqi;

import java.io.IOException;

import okhttp3.Connection;
import okhttp3.Request;
import okhttp3.Response;

/**
* Created by DELL on 2017/10/21.
*/

public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain{
Request request();
Response proceed(Request request)throws IOException;
Connection connection();

}

}

LoggingInterceptor

package lanjieqi;

import android.util.Log;

import java.io.IOException;

import okhttp3.*;
import okhttp3.internal.platform.Platform;

/**
* Created by DELL on 2017/10/21.
*/

public class LoggingInterceptor implements okhttp3.Interceptor {



public static String TAG = "LogInterceptor";

@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long startTime = System.currentTimeMillis();
Response response = chain.proceed(chain.request());
long endTime = System.currentTimeMillis();
long duration=endTime-startTime;
MediaType mediaType = response.body().contentType();
String content = response.body().string();
Log.d(TAG,"\n");
Log.d(TAG,"----------Start----------------");
Log.d(TAG, "| "+request.toString());
String method=request.method();
if("POST".equals(method)){
StringBuilder sb = new StringBuilder();
if (request.body() instanceof FormBody) {
FormBody body = (FormBody) request.body();
for (int i = 0; i < body.size(); i++) {
sb.append(body.encodedName(i) + "=" + body.encodedValue(i) + ",");
}
sb.delete(sb.length() - 1, sb.length());
Log.d(TAG, "| RequestParams:{"+sb.toString()+"}");
}
}
Log.d(TAG, "| Response:" + content);
Log.d(TAG,"----------End:"+duration+"毫秒----------");
return response.newBuilder()
.body(ResponseBody.create(mediaType, content))
.build();
}
}

Model包

ShopModel


package model;

import com.google.gson.Gson;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import bean.Shop;
import common.Api;
import okhttp3.Call;
import okhttp3.Response;
import utils.Callbak;
import utils.NetRequestData;

/**
* Created by DELL on 2017/10/21.
*/

public class ShopModel {


private onShop onShop;
public void getShop(int page){
Map params=new HashMap<>();
params.put("page",page+"");
NetRequestData.call(Api.URL, params, new Callbak() {
@Override
public void RequestSuccess(Call call, Response response) {
try {
String result = response.body().string();
Gson gson=new Gson();
Shop shop = gson.fromJson(result, Shop.class);
List data = https://www.it610.com/article/shop.data;
System.out.println("==============="+data.size());
String code = shop.code;
String msg = shop.msg;
if("0".equals(code))
{
onShop.onShopSuccess(data);
}
else
{
onShop.onShopFailure(msg);
}

} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public void RequestFaliure(Call call, IOException e) {
onShop.onFailure(call,e);
}
});

}


public void setOnShop(ShopModel.onShop onShop) {
this.onShop = onShop;
}

public interface onShop{
void onShopSuccess(List data);
void onShopFailure(String msg);
void onFailure(Call call,IOException e);
}



}


presenter包 ShopPresenter

package presenter;

import java.io.IOException;
import java.util.List;

import bean.Shop;
import model.ShopModel;
import okhttp3.Call;
import view.ShopView;

/**
* Created by DELL on 2017/10/21.
*/

public class ShopPresenter implements ShopModel.onShop {

private ShopModel shopModel;
private ShopView shopView;

public ShopPresenter(ShopView shopView) {
this.shopView = shopView;
shopModel=new ShopModel();
shopModel.setOnShop(this);
}


public void requestShop(int page){
shopModel.getShop(page);

}
@Override
public void onShopSuccess(List data) {
shopView.onShopSuccess(data);

}

@Override
public void onShopFailure(String msg) {
shopView.onShopFailure(msg);

}

@Override
public void onFailure(Call call, IOException e) {
shopView.onFailure(call,e);

}
}





View
ShopView
package view;

import java.io.IOException;
import java.util.List;

import bean.Shop;
import okhttp3.Call;

/**
* Created by DELL on 2017/10/21.
*/

public interface ShopView {
void onShopSuccess(List data);
void onShopFailure(String msg);
void onFailure(Call call, IOException e);
}


Utils包
Callbak类

package utils;

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Response;

/**
* Created by DELL on 2017/10/21.
*/

public interface Callbak {
void RequestSuccess(Call call, Response response);
void RequestFaliure(Call call, IOException e);
}





CrashHandler

package utils;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
/**
* Created by DELL on 2017/10/21.
*/

public class CrashHandler implements Thread.UncaughtExceptionHandler {

public static final String TAG = "CrashHandler";

//系统默认的UncaughtException处理类
private Thread.UncaughtExceptionHandler mDefaultHandler;
//CrashHandler实例
private static CrashHandler INSTANCE = new CrashHandler();
//程序的Context对象
private Context mContext;
//用来存储设备信息和异常信息
private Map infos = new HashMap();

//用于格式化日期,作为日志文件名的一部分
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");

/** 保证只有一个CrashHandler实例 */
private CrashHandler() {
}

/** 获取CrashHandler实例 ,单例模式 */
public static CrashHandler getInstance() {
return INSTANCE;
}

/**
* 初始化
*
* @param context
*/
public void init(Context context) {
mContext = context;
//获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
//设置该CrashHandler为程序的默认处理器
Thread.setDefaultUncaughtExceptionHandler(this);
}

/**
* 当UncaughtException发生时会转入该函数来处理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
//如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Log.e(TAG, "error : ", e);
}
//退出程序
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
}

/**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
*
* @param ex
* @return true:如果处理了该异常信息; 否则返回false.
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
//使用Toast来显示异常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
//收集设备参数信息
collectDeviceInfo(mContext);
//保存日志文件
saveCrashInfo2File(ex);
return true;
}

/**
* 收集设备参数信息
* @param ctx
*/
public void collectDeviceInfo(Context ctx) {
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
if (pi != null) {
String versionName = pi.versionName == null ? "null" : pi.versionName;
String versionCode = pi.versionCode + "";
infos.put("versionName", versionName);
infos.put("versionCode", versionCode);
}
} catch (NameNotFoundException e) {
Log.e(TAG, "an error occured when collect package info", e);
}
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
infos.put(field.getName(), field.get(null).toString());
Log.d(TAG, field.getName() + " : " + field.get(null));
} catch (Exception e) {
Log.e(TAG, "an error occured when collect crash info", e);
}
}
}

/**
* 保存错误信息到文件中
*
* @param ex
* @return返回文件名称,便于将文件传送到服务器
*/
private String saveCrashInfo2File(Throwable ex) {

StringBuffer sb = new StringBuffer();
for (Map.Entry entry : infos.entrySet()) {
String key = entry.getKey();
String value = https://www.it610.com/article/entry.getValue();
sb.append(key + "=" + value + "\n");
}

Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
printWriter.close();
String result = writer.toString();
sb.append(result);
try {
long timestamp = System.currentTimeMillis();
String time = formatter.format(new Date());
String fileName = "crash-" + time + "-" + timestamp + ".log";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String path = "/mnt/sdcard/";
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
FileOutputStream fos = new FileOutputStream(path + fileName);
fos.write(sb.toString().getBytes());
fos.close();
}
return fileName;
} catch (Exception e) {
Log.e(TAG, "an error occured while writing file...", e);
}
return null;
}
}



NetRequestDate类
package utils;

import java.io.IOException;
import java.util.Map;

import lanjieqi.LoggingInterceptor;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
* Created by DELL on 2017/10/21.
*/

public class NetRequestData {

public static void call(String url, Map params, final Callbak callbak){


OkHttpClient client=new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();

FormBody.Builder body= new FormBody.Builder();
for (Map.Entry stringStringEntry : params.entrySet()) {

body.add(stringStringEntry.getKey(),stringStringEntry.getValue());
}

RequestBody build = body.build();

Request request=new Request.Builder().url(url).header("User-Agent", "OkHttp Example").post(build).build();

client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {

callbak.RequestFaliure(call,e);
}

@Override
public void onResponse(Call call, Response response) throws IOException {
callbak.RequestSuccess(call,response);
}
});


}




}


CountDownProgress 属性动画

package view;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.CountDownTimer;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;

import com.example.dell.zhoukao3.R;

/**
* Created by DELL on 2017/10/21.
*/

public class CountDownProgress extends View {

private static int defaultCircleSolideColor = Color.BLUE;
private static int defaultCircleStrokeColor = Color.WHITE;
private static int defaultCircleStrokeWidth = 8;
private static int defaultCircleRadius = 200;
private static int progressColor = Color.RED;
private static int progressWidth = 4;
private static int smallCircleSolideColor = Color.BLACK;
private static int smallCircleStrokeColor = Color.WHITE;
private static float smallCircleStrokeWidth = 8;
private static float smallCircleRadius = 30;
private static int textColor = Color.BLACK;
private static float textSize = 30;
private static Paint defaultCriclePaint;
private static Paint progressPaint;
private static Paint smallCirclePaint;
private static Paint smallCircleSolidePaint;
private static Paint textPaint;
private static float currentAngle;
private static String textDesc;
private static long countdownTime;
private static int mStartSweepValue = https://www.it610.com/article/-90;


public CountDownProgress(Context context) {
super(context);
}

public CountDownProgress(Context context, AttributeSet attrs) {
super(context, attrs);
}

public CountDownProgress(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//获取自定义属性
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CountDownProgress);
int indexCount = typedArray.getIndexCount();
for(int i=0; iint attr = typedArray.getIndex(i);
switch (attr){
case R.styleable.CountDownProgress_default_circle_solide_color:
defaultCircleSolideColor = typedArray.getColor(attr, defaultCircleSolideColor);
break;
case R.styleable.CountDownProgress_default_circle_stroke_color:
defaultCircleStrokeColor = typedArray.getColor(attr, defaultCircleStrokeColor);
break;
case R.styleable.CountDownProgress_default_circle_stroke_width:
defaultCircleStrokeWidth = (int) typedArray.getDimension(attr, defaultCircleStrokeWidth);
break;
case R.styleable.CountDownProgress_default_circle_radius:
defaultCircleRadius = (int) typedArray.getDimension(attr, defaultCircleRadius);
break;
case R.styleable.CountDownProgress_progress_color:
progressColor = typedArray.getColor(attr, progressColor);
break;
case R.styleable.CountDownProgress_progress_width:
progressWidth = (int) typedArray.getDimension(attr, progressWidth);
break;
case R.styleable.CountDownProgress_small_circle_solide_color:
smallCircleSolideColor = typedArray.getColor(attr, smallCircleSolideColor);
break;
case R.styleable.CountDownProgress_small_circle_stroke_color:
smallCircleStrokeColor = typedArray.getColor(attr, smallCircleStrokeColor);
break;
case R.styleable.CountDownProgress_small_circle_stroke_width:
smallCircleStrokeWidth = (int) typedArray.getDimension(attr, smallCircleStrokeWidth);
break;
case R.styleable.CountDownProgress_small_circle_radius:
smallCircleRadius = (int) typedArray.getDimension(attr, smallCircleRadius);
break;
case R.styleable.CountDownProgress_text_color:
textColor = typedArray.getColor(attr, textColor);
break;
case R.styleable.CountDownProgress_text_size:
textSize = (int) typedArray.getDimension(attr, textSize);
break;
}
}
typedArray.recycle();
}

private void setPaint() {
//默认圆
defaultCriclePaint = new Paint();
defaultCriclePaint.setAntiAlias(true); //抗锯齿
defaultCriclePaint.setDither(true); //防抖动
defaultCriclePaint.setStyle(Paint.Style.STROKE);
defaultCriclePaint.setStrokeWidth(defaultCircleStrokeWidth);
defaultCriclePaint.setColor(defaultCircleStrokeColor); //这里先画边框的颜色,后续再添加画笔画实心的颜色
//默认圆上面的进度弧度
progressPaint = new Paint();
progressPaint.setAntiAlias(true);
progressPaint.setDither(true);
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setStrokeWidth(progressWidth);
progressPaint.setColor(progressColor);
progressPaint.setStrokeCap(Paint.Cap.ROUND); //设置画笔笔刷样式
//进度上面的小圆
smallCirclePaint = new Paint();
smallCirclePaint.setAntiAlias(true);
smallCirclePaint.setDither(true);
smallCirclePaint.setStyle(Paint.Style.STROKE);
smallCirclePaint.setStrokeWidth(smallCircleStrokeWidth);
smallCirclePaint.setColor(smallCircleStrokeColor);
//画进度上面的小圆的实心画笔(主要是将小圆的实心颜色设置成白色)
smallCircleSolidePaint = new Paint();
smallCircleSolidePaint.setAntiAlias(true);
smallCircleSolidePaint.setDither(true);
smallCircleSolidePaint.setStyle(Paint.Style.FILL);
smallCircleSolidePaint.setColor(smallCircleSolideColor);

//文字画笔
textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setDither(true);
textPaint.setStyle(Paint.Style.FILL);
textPaint.setColor(textColor);
textPaint.setTextSize(textSize);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setPaint();
canvas.save();
canvas.translate(getPaddingLeft(), getPaddingTop());
//画默认圆
canvas.drawCircle(defaultCircleRadius, defaultCircleRadius, defaultCircleRadius, defaultCriclePaint);

//画进度圆弧
//currentAngle = getProgress()*1.0f/getMax()*360;
canvas.drawArc(new RectF(0, 0, defaultCircleRadius*2, defaultCircleRadius*2),mStartSweepValue, 360*currentAngle,false,progressPaint);
//画中间文字
// String text = getProgress()+"%";
//获取文字的长度的方法
/* float textWidth = textPaint.measureText(textDesc);
float textHeight = (textPaint.descent() + textPaint.ascent()) / 2;
canvas.drawText(textDesc, defaultCircleRadius - textWidth/2, defaultCircleRadius - textHeight, textPaint); */

//画小圆
float currentDegreeFlag = 360*currentAngle;
float smallCircleX = 0,smallCircleY = 0;
float hudu = (float) Math.abs(Math.PI * currentDegreeFlag / 180); //Math.abs:绝对值 ,Math.PI:表示π , 弧度 = 度*π / 180
smallCircleX = (float) Math.abs(Math.sin(hudu) * defaultCircleRadius + defaultCircleRadius);
smallCircleY = (float) Math.abs(defaultCircleRadius -Math.cos(hudu) * defaultCircleRadius);
canvas.drawCircle(smallCircleX, smallCircleY, smallCircleRadius, smallCirclePaint);
canvas.drawCircle(smallCircleX, smallCircleY, smallCircleRadius - smallCircleStrokeWidth, smallCircleSolidePaint); //画小圆的实心

canvas.restore();

}

/**
* 如果该View布局的宽高开发者没有精确的告诉,则需要进行测量,如果给出了精确的宽高则我们就不管了
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize;
int heightSize;
int strokeWidth = Math.max(defaultCircleStrokeWidth, progressWidth);
if(widthMode != MeasureSpec.EXACTLY){
widthSize = getPaddingLeft() + defaultCircleRadius*2 + strokeWidth + getPaddingRight();
widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
}
if(heightMode != MeasureSpec.EXACTLY){
heightSize = getPaddingTop() + defaultCircleRadius*2 + strokeWidth + getPaddingBottom();
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
}

super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

//属性动画
public void startCountDownTime(final OnCountdownFinishListener countdownFinishListener){
setClickable(false);
ValueAnimator animator = ValueAnimator.ofFloat(0, 1.0f);
//动画时长,让进度条在CountDown时间内正好从0-360走完,这里由于用的是CountDownTimer定时器,倒计时要想减到0则总时长需要多加1000毫秒,所以这里时间也跟着+1000ms
animator.setDuration(3000);
animator.setInterpolator(new LinearInterpolator()); //匀速
animator.setRepeatCount(0); //表示不循环,-1表示无限循环
//值从0-1.0F 的动画,动画时长为countdownTime,ValueAnimator没有跟任何的控件相关联,那也正好说明ValueAnimator只是对值做动画运算,而不是针对控件的,我们需要监听ValueAnimator的动画过程来自己对控件做操作
//添加监听器,监听动画过程中值的实时变化(animation.getAnimatedValue()得到的值就是0-1.0)
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
/**
* 这里我们已经知道ValueAnimator只是对值做动画运算,而不是针对控件的,因为我们设置的区间值为0-1.0f
* 所以animation.getAnimatedValue()得到的值也是在[0.0-1.0]区间,而我们在画进度条弧度时,设置的当前角度为360*currentAngle,
* 因此,当我们的区间值变为1.0的时候弧度刚好转了360度
*/
currentAngle = (float) animation.getAnimatedValue();
//Log.e("currentAngle",currentAngle+"");
invalidate(); //实时刷新view,这样我们的进度条弧度就动起来了
}
});
//开启动画
animator.start();
//还需要另一个监听,监听动画状态的监听器
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}

@Override
public void onAnimationEnd(Animator animation) {
//倒计时结束的时候,需要通过自定义接口通知UI去处理其他业务逻辑
if(countdownFinishListener != null){
countdownFinishListener.countdownFinished();
}
if(countdownTime > 0){
setClickable(true);
}else{
setClickable(false);
}
}

@Override
public void onAnimationCancel(Animator animation) {
}

@Override
public void onAnimationRepeat(Animator animation) {
}
});
//调用倒计时操作
countdownMethod();
}

//倒计时的方法
private void countdownMethod(){
new CountDownTimer(countdownTime+1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
//Log.e("time",countdownTime+"");
countdownTime = countdownTime-1000;
textDesc = countdownTime/1000 + "″";
//countdownTime = countdownTime-1000;
Log.e("time",countdownTime+"");
//刷新view
invalidate();
}
@Override
public void onFinish() {
//textDesc = 0 + "″";
textDesc = "时间到";
//同时隐藏小球
smallCirclePaint.setColor(getResources().getColor(android.R.color.transparent));
smallCircleSolidePaint.setColor(getResources().getColor(android.R.color.transparent));
//刷新view
invalidate();
}
}.start();
}
public void setCountdownTime(long countdownTime){
this.countdownTime = countdownTime;
textDesc = countdownTime / 1000 + "″";
}

public interface OnCountdownFinishListener {
void countdownFinished();
}
}





attr






















































权限




依赖


compile 'com.squareup.okhttp3:okhttp:3.9.0'
compile 'org.kie.modules:com-google-code-gson:6.5.0.Final'
compile 'com.google.code.gson:gson:2.8.2'
compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.jcodecraeer:xrecyclerview:1.3.2'



Main布局

xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.dell.zhoukao3.MainActivity"
android:orientation="vertical"
android:weightSum="1">

android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="https://www.it610.com/article/@mipmap/ic_launcher" />




android:id="@+id/countdownProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center"
/>





Main2布局

xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.dell.zhoukao3.Main2Activity">




android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent">





Main3布局

xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.dell.zhoukao3.Main3Activity">

android:id="@+id/wv"
android:layout_width="match_parent"
android:layout_height="match_parent">




rv_item布局

android:layout_width="match_parent"
android:layout_height="match_parent">

android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="84dp"
android:src="https://www.it610.com/article/@mipmap/ic_launcher"
android:padding="10dp"/>

android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">

android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title"
android:padding="5dp"/>

android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="price"
android:padding="5dp"/>




rv_item1布局

android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="84dp"
android:src="https://www.it610.com/article/@mipmap/ic_launcher"
android:padding="10dp"/>

android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">

android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title"
android:padding="5dp"/>

android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="price"
android:padding="5dp"/>





rv_item2

android:layout_width="match_parent"
android:layout_height="match_parent">

android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="84dp"
android:src="https://www.it610.com/article/@mipmap/ic_launcher"
android:padding="10dp"/>

android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">

android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title"
android:padding="5dp"/>

android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="price"
android:padding="5dp"/>






【adapter|okHttp网络请求2——MVP】rv_item3

android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

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

android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="https://www.it610.com/article/@mipmap/ic_launcher"/>

android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="https://www.it610.com/article/@mipmap/ic_launcher"/>

android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">

android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title"
android:padding="5dp"/>

android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="price"
android:padding="5dp"/>





    推荐阅读