概述
这篇博客也算是本人从事开发以来的一个总结,以前写博客是为了装逼,现在是为了成长,一个项目如果刚开始的框架没有搭建好,接下来的维护工作将变得异常困难,我们公司的按项目就是因为一开始的框架没有搭建好,只迭代了两个版本便维护不下去了,只能是请高人重新设计的框架,一切重新来过。
不同类型的项目对框架的要求自然不同,但是有一点是相同的,那就是,首先对基础语法进行封装,相应工具类、方法样式的封装,前期的封装可以避免后期项目无休止的重构代码,也就不会出现因频繁的改动需求导致代码大量冗余。
废话不多说,进入正题,要开始一个移动端项目搭建,一个最基本的前提条件就是要有完整的条理的产品需求,专业的产品原型图,这一切都是产品经理来做的,如果你们公司没有产品经理,那么你也就只能自求多福了,当然你有一个天天把就跟淘宝一样这句话挂在嘴边的二逼产品经理,你也只能自求多福了。
对一个Android项目而言,前界面样式的抽取,方法的封装,工具类的导入,第三方sdk的继承很重要
让我们从BaseActivity和BaseFragment的封装开始吧,为什么要封装BaseFragment和BaseActivity呢,我想你不会愿意同样的方法同样的代码照抄十遍吧,在BaseActivity和BaseFragment中我们可以定义一些接口或者抽象方法,以方便在其子类中执行
代码如下:
BaseActivity(abstract)这样是为了一些抽象方法实现,而且不用再清单文件中注册
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.xxx.baseproject.MyApp;
import com.xxx.baseproject.R;
import com.xxxx.baseproject.util.NetUtils;
import com.xxx.baseproject.util.StatusBarCompat;
/**
* Created by xuenan on 2016/5/23.
*/
public abstract class BaseActivity extends AppCompatActivity{
//布局文件ID
protected abstract int getContentViewId();
//Activity基本样式,功能
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//将ActionBar隐藏
/**
*说到Actionbar,这是一个又丑又没有用的东西,还得想方设法隐藏它
*隐藏ActionBar的方法有好几种,
*一种是在Theme主题中设定Theme.AppCompat.Light.NoActionBar
*或者在某个activity的主题中设定,这都是在清单文件中操作的
*第二种就是在Activity调用setContentView()之前调用
*requestWindowFeature(Window.FEATURE_NO_TITLE);
*或者
*requestWindowFeature(Window.FEATURE_NO_TITLE);
*supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
*这两种方法的区别在于你的Activituy所继承的是什么Activity
*像本文,继承的是v7包中的AppCompatActivity,选用后者
*/
//实现沉浸式状态栏,后边会说
StatusBarCompat.compat(this);
MyApp app = (MyApp) getApplication();
//将每一个Activity都加入一个集合,用于程序退出
app.addActivity(this);
//用于网络监测
if(!NetUtils.isConnected(BaseActivity.this)){
AlertDialog.Builder builder = new AlertDialog.Builder(BaseActivity.this);
builder.setIcon(R.mipmap.ic_launcher);
builder.setTitle("提示");
builder.setMessage("当前没有可用网络,是否进入网络设置界面");
builder.setNegativeButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
NetUtils.openSetting(BaseActivity.this);
}
});
builder.setPositiveButton("取消",null);
builder.create().show();
}
}
}
BaseFragment(abstract)道理同上
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by xuenan on 2016/5/23.
* 一般情况下,为了向下兼容,我们采用v4包中的Fragment
*/
public abstract class BaseFragment extends Fragment{
protected BaseActivity mActivity;
//封装抽象方法用于在fragment中初始化控件,增加代码的条理性
protected abstract void initView(View view, Bundle savedInstanceState);
//获取fragment布局文件ID
protected abstract int getLayoutId();
//获取宿主Activity,不在使用getActivity()获取Activity对象
protected BaseActivity getHoldingActivity() {
return mActivity;
}
//在api23中此方法已经过时,用下边那个重载的方法代替,如果是在22及其以下则没有过时 照样使用该方法
// @Override
// public void onAttach(Activity activity) {
// super.onAttach(activity);
// this.mActivity = (BaseActivity) activity;
// }
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.mActivity = (BaseActivity) context;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(getLayoutId(), container, false);
initView(view, savedInstanceState);
return view;
}
}
BaseFeagment的意义不仅仅在于此,能够获取Fragent所依赖的Activity对我们而言也是至关重要的,众所周知,getActivity()的方式来获取Activity的对象在有些时候显得并不是那么靠谱,而有些控件又必须是依赖于Activity的,比如ActionBar,ToolBar,,在fragment中可以采用上述方法获取Activity对象,再设置ToolBar,getHoldingActivity().setSupportActionBar(toolbar)…….
对一个Android程序而言,有一个全局的Application(不要忘记在清单文件中注册)是很重要的,主要用来初始化一些东西,比如地图,推送,异常检测,网络请求。。。等等东西
import android.app.Activity;
import android.app.Application;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
import com.xxx.baseproject.util.CrashHandler;
import com.xxx.baseproject.util.FunctionUtils;
import com.xxx.baseproject.util.LogUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Created by xuenan on 2015/12/31.
*/
public class MyApp extends Application{
private static MyApp instance;
/**
* 01. 建立 请求队列
* 02. 将 请求队列 加入到 AndroidMain.xml中
* 03.
*/
//本例使用Volley作为请求框架,它代表请求队列
private static RequestQueue queue;
//存放Activity的List集合
private List<Activity> activityList = new ArrayList<>();
//单例模式获得Application对象
public static MyApp getInstance() {
return instance;
}
@Override
public void onCreate() {
super.onCreate();
instance=this;
//异常处理类,实现了UncaughtExceptionHandler接口,
//当程序发生异常时使程序优雅的退出
CrashHandler crashHandler = CrashHandler.getInstance();
//用单例模式或者Volley请求队列
queue= Volley.newRequestQueue(this.getApplicationContext());
//对ImageLoader进行初始化
FunctionUtils.setCustomImageLaoder(getApplicationContext());
}
//入口
public static RequestQueue getQueue(){
return queue;
}
/**
* add the activity in to a list end
* @param activity
*/
public void addActivity(Activity activity) {
try {
if (activity != null && activityList != null) {
int size = activityList.size();
if (checkActivityIsVasivle(activity)) {
removeActivity(activity);
activityList.add(activityList.size(), activity);
} else {
activityList.add(activity);
}
size = activityList.size();
for (int i = 0; i < size; i++) {
LogUtils.i("addActivity ==[" + i + "]" + " " + activityList.get(i));
}
}
} catch (Exception e) {
LogUtils.e("addActivity" + e.getMessage());
}
}
/**
* remove the finished activity in the list.
* @param activity
* the activity is removed from activityList
*/
public void removeActivity(Activity activity) {
try {
if (activityList != null) {
activityList.remove(activity);
LogUtils.i("removeActivity==" + " " + activity + "activityList.size===" + activityList.size());
}
} catch (Exception e) {
LogUtils.e("removeActivity" + e.getMessage());
}
}
/**
* 判定某个Activity的状态,
* */
public boolean checkActivityIsVasivle(Activity activity) {
LogUtils.i(" " + activityList.contains(activity));
return activityList.contains(activity);
}
/**
* finish all the activity in the list.
*干掉所有的Activity用于程序退出
* the activity calling this method hold the context
*/
public void finishAllActivity() {
if (activityList != null) {
int size = activityList.size();
for (int i = size - 1; i >= 0; i--) {
Activity activity = activityList.get(i);
if (activity != null) {
activity.finish();
}
LogUtils.i("finishAllActivity ==[" + i + "]" + " " + activity);
activityList.remove(activity);
}
}
}
}
网络请求框架的封装,以Volley为例子
请求回调
import com.android.volley.Response;
import com.android.volley.VolleyError;
/**
* 抽象出 成功的监听和失败的监听
* 用来回调信息
* @author yuan
*
* @param <T>
*/
public abstract class VolleyHandler<T> {
public Response.Listener<T> reqLis;
public Response.ErrorListener reqErr;
public VolleyHandler() {
// 初始化 变量
reqLis = new reqListener();
reqErr = new reqErrorListener();
}
public abstract void reqSuccess(T response);
public abstract void reqError(String error);
/**
* 成功后的监听
*
* @author yuan
*
*/
public class reqListener implements Response.Listener<T> {
@Override
public void onResponse(T response) {
// 使用抽象函数 设置 回调函数 reqSuccess
reqSuccess(response);
}
}
/**
* 失败后的监听
*
* @author yuan
*
*/
public class reqErrorListener implements Response.ErrorListener {
@Override
public void onErrorResponse(VolleyError error) {
// 设置回调函数 使用 抽象方法 ReqError
reqError(error.getMessage());
}
}
}
请求方法封装
import android.app.Activity;
import android.graphics.Bitmap;
import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request.Method;
import com.android.volley.RetryPolicy;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageRequest;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.StringRequest;
import com.xxx.baseproject.MyApp;
import org.json.JSONObject;
import java.util.Map;
/**
* @author xuenan
*请求超时设置三个参数的含义 等待时间 重复请求次数 下次请求等待时间
*/
public class VolleyHttpRequest{
/** 1.
* StringRequest GET方式
* @param url 地址
* @param volleyRequest 回调函数
*/
public static void String_request(String url,VolleyHandler<String> volleyRequest){
Volley_StringRequest(Method.GET, url,null, volleyRequest);
}
/** 1.
* StringRequset POST方式
* @param url 地址
* @param map 参数
* @param volleyRequest 回调函数
*/
public static void String_request(String url,final Map<String,String> map,VolleyHandler<String> volleyRequest){
Volley_StringRequest(Method.POST,url,map,volleyRequest);
}
/**1.
* 封装 StringRequest 数据请求
* @param method 方式
* @param url 地址
* @param params 参数
* @param volleyRequest 回调对象
*/
private static void Volley_StringRequest(int method,String url,final Map<String,String> params,VolleyHandler<String> volleyRequest){
StringRequest stringrequest=new StringRequest(method, url,volleyRequest.reqLis,volleyRequest.reqErr){
//传递参数
@Override
protected Map<String, String> getParams() throws AuthFailureError {
return params;
}
//设置请求超时
@Override
public RetryPolicy getRetryPolicy() {
RetryPolicy retryPolicy = new DefaultRetryPolicy(15000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
return retryPolicy;
}
};
stringrequest.setTag("stringrequest");
MyApp.getQueue().add(stringrequest);
}
/**2.
* JsonObjectRequest GET 请求
* @param url 请求地址
* @param volleyRequest 回调函数对象
*/
public static void JsonObject_Request(String url,VolleyHandler<JSONObject> volleyRequest){
Volley_JsonObjectRequest(Method.GET, url, null, volleyRequest);
}
/**2
* JsonObjectRequest POST 请求
* @param url 请求地址
* @param jsonObject 请求参数
* @param volleyRequest 回调函数对象
*/
public static void JsonObject_Request(String url,JSONObject jsonObject,VolleyHandler<JSONObject> volleyRequest){
Volley_JsonObjectRequest(Method.POST,url,jsonObject,volleyRequest);
}
/**2.
* 封装 JsonObjectRequest 请求方法
* @param method 方式
* @param url 地址
* @param jsonObject 参数
* @param volleyRequest 回调函数对象
*/
private static void Volley_JsonObjectRequest(int method,String url,JSONObject jsonObject,VolleyHandler<JSONObject> volleyRequest){
JsonObjectRequest jsonObjectRequest=new JsonObjectRequest(method,url,jsonObject,volleyRequest.reqLis,volleyRequest.reqErr){
//设置请求超时
@Override
public RetryPolicy getRetryPolicy() {
RetryPolicy retryPolicy = new DefaultRetryPolicy(15000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
return retryPolicy;
}
};
jsonObjectRequest.setTag("jsonObjectRequest");
MyApp.getQueue().add(jsonObjectRequest);
}
/**3.
* ImageRequest 默认大小 原图不变
* @param url 地址
* @param volleyRequest 回调函数
*/
public static void Image_request(String url,VolleyHandler<Bitmap> volleyRequest){
Volley_ImageRequest(url, 0, 0, volleyRequest);
}
/**3.
* ImageRequest 自定义的缩放
* @param url 地址
* @param maxWidth 最大宽度
* @param maxHeight 最大高度
* @param volleyRequest 回调函数
*/
public static void Image_request(String url,int maxWidth,int maxHeight,VolleyHandler<Bitmap> volleyRequest){
Volley_ImageRequest(url, maxWidth, maxHeight, volleyRequest);
}
/**3.
* 封装 ImageRequest 请求方法
* @param url 地址
* @param maxWidth 最大宽度
* @param maxHeight 最大高度
* @param volleyRequest 回调函数对象
*/
private static void Volley_ImageRequest(String url,int maxWidth,int maxHeight,VolleyHandler<Bitmap> volleyRequest){
ImageRequest imageRequest=new ImageRequest(url,volleyRequest.reqLis, maxWidth, maxHeight, Bitmap.Config.ARGB_8888,volleyRequest.reqErr){
//设置请求超时
@Override
public RetryPolicy getRetryPolicy() {
RetryPolicy retryPolicy = new DefaultRetryPolicy(15000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
return retryPolicy;
}
};
imageRequest.setTag("imageRequest");
MyApp.getQueue().add(imageRequest);
}
/**
* 4.
* 自定义图片的宽度值
* @param url
* @param imageListener
* @param maxWidth
* @param maxHidth
*/
public static void Image_Loader(String url,ImageLoader.ImageListener imageListener,int maxWidth,int maxHidth){
Volley_ImageLoader(url, imageListener, maxWidth, maxHidth);
}
/** 4.
* 默认值,原始比例
* @param url 地址
* @param imageListener 图片监听
*/
public static void Image_Loader(String url,ImageLoader.ImageListener imageListener){
Volley_ImageLoader(url,imageListener,0,0);
}
/** 4.
* 封装 ImageLoader 方法
* @param url 地址
* @param imageListener 图片监听
* @param maxWidth
* @param maxHidth
*/
private static void Volley_ImageLoader(String url,ImageLoader.ImageListener imageListener,int maxWidth,int maxHidth){
// 设置 图片缓存 :体现 imageLoader的优势
// 使用 LruBitmap + ImageCache 实现
// 实例化对象
ImageLoader imageLoader = new ImageLoader(MyApp.getQueue(),
new VolleyBitmapCache());
// 加载图片 图片监听 (默认图片,错误图片) 和 imageView
imageLoader.get(url, imageListener,maxWidth,maxHidth);
}
/**
* 取消某个界面的网络 请求
* @param activity 请求所在的activity
*/
public static void CancelAllRequest(Activity activity){
MyApp.getQueue().cancelAll(activity);
}
}
//上边类中图片内存缓存的工具类,在这一工具类中,我去掉了内存缓存
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.util.LruCache;
import com.android.volley.toolbox.ImageLoader.ImageCache;
@SuppressLint("NewApi")
public class VolleyBitmapCache implements ImageCache{
//使用LruCache 实现图片缓存 :
private LruCache<String,Bitmap> cache;
//设置最大的 尺寸值
public VolleyBitmapCache() {
//构造方法 实现 LruCache 缓存 图片
int maxSize=10*1024*1024;
cache=new LruCache<String,Bitmap>(maxSize){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight();
}
};
}
@Override
public Bitmap getBitmap(String url) {
// 得到
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
// 设置
cache.put(url, bitmap);
}
}
在开发中为了实现一些效果,经常需要自定义View来实现设计需求,自定义View分为以下几种:
1:继承View,
重写其onDraw方法,用画笔在画布上绘制 所需要的图形
Paint paint;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);// 重写onDraw方法
}
重写onMeasure方法,测量View的高度
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
}
2:继承某个现有控件,重写其事件分发事件处理比如:LinearLayout,ViewGroup,ViewPager等。这种方式主要是为了处理父布局和子布局的冲突事件,故onTouchEvent,onInterceptTouchEvent,disPatchTouchEvent这三个方法的重写是重点
@Override
public boolean onTouchEvent(MotionEvent ev) {
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
}
3:对现有控件进行组合,以实现预期效果,比如在实际开发中经常用到的搜索框,Android原生SearchVeiw的样式比较丑,一般我们是将EditText等控件放到一个ViewGroup中这样自定义View的方式来实现效果
本片博文列举几个常见的View
1.1:自定义View实现折线图
package com.xxx.baseproject.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import com.xxx.baseproject.model.PointBean;
import java.util.ArrayList;
import java.util.List;
/**
*
* 折线图
*
*/
public class ChartView extends View {
// 传递过来的数据
public String[] XLabel;
public String[] Data;
public float xPoint = 30; // (以320宽度的分辨率为准,其他分辨率*系数)
public float YPoint = 220; // (以320宽度的分辨率为准,其他分辨率*系数)
public float YLength = 200;// (以320宽度的分辨率为准,其他分辨率*系数)
public float xLength;// X轴的刻度(屏幕的宽度-左右两边的间隔)
public float xScale;// X轴的刻度长度
public float YScale;// y轴的刻度长度
public float eachYLabel;// Y轴应该显示的值
public float halfXLabel;// X轴的刻度长度的2/3 用以显示X轴的坐标值
private float selectX;// 选中区域要显示的圆点的 x坐标
private float xyExtra = 20;// XY轴空余的距离
private float displacement = 5;
private float textSize = 8;
private float circleSize = 2;// 圆点的大小
private float radio;// 不同分辨率的 比率(以320为基数)
private String selectData = "";// 选中之后需要显示的数据
private int screenWidth;
private int screenHeight;
private RectF rectF;
private List<PointBean> allpoint = new ArrayList<PointBean>();
private Paint textPaint;
private Paint linePaint;
private Paint dataPaint;
private Paint selectBkgPaint;
private Paint selectCirclePaint;
public ChartView(Context context) {
super(context);
}
public void SetInfo(String[] AllData,String[]AllDate,
Display display) {
XLabel = AllDate;
Data = AllData;
DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);
this.screenWidth = outMetrics.widthPixels;
this.screenHeight = outMetrics.heightPixels;
radio = screenWidth / 320;// (以320的分辨率为基准)
xPoint = xPoint * radio;// X轴左右两边的间隔
//xLength = screenWidth-100;
xLength = screenWidth - xPoint*2;// X轴的长度 左右两边空余xPoint的刻度,,使x轴右侧流出一些缝隙来
//xLength = screenWidth - xPoint-40;
xyExtra = xyExtra * radio;
xScale = (xLength - xyExtra) / XLabel.length; // X轴的刻度间隔为长度-最右边空余的距离
halfXLabel = xScale * 2 / 3;// X轴刻度的一半值(X轴刻度值在中间显示)
YPoint = YPoint * radio;
YLength = YLength * radio;
displacement = displacement * radio;// Y轴显示的文字(金额)
YScale = (YLength - xyExtra) / 5;// Y轴的刻度为长度-最上边的距离 除以个数
eachYLabel = max(Data) / 5;// Y轴的刻度值为(最大数/5)
textSize = textSize * radio;
circleSize = circleSize * radio;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);// 重写onDraw方法
// 文本的画笔//x,y轴的文本
textPaint = new Paint();
textPaint.setStyle(Paint.Style.STROKE);
textPaint.setAntiAlias(true);// 去锯齿
textPaint.setColor(Color.parseColor("#006400"));// 颜色
textPaint.setTextSize(textSize); // 设置轴文字大小
// 线的画笔 x,y轴+横线
linePaint = new Paint();
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setAntiAlias(true);// 去锯齿
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setAntiAlias(true);// 去锯齿
linePaint.setColor(Color.parseColor("#00EE00"));// 颜色
// 曲线和未选中圆点的画笔
dataPaint = new Paint();
dataPaint.setStyle(Paint.Style.FILL);
dataPaint.setAntiAlias(true);// 去锯齿
dataPaint.setColor(Color.parseColor("#EE1289"));// 颜色
dataPaint.setTextSize(textSize); // 设置轴文字大小
dataPaint.setStrokeWidth(4);
// 选中之后日期背景的画笔
selectBkgPaint = new Paint();
selectBkgPaint.setStyle(Paint.Style.FILL_AND_STROKE);
selectBkgPaint.setAntiAlias(true);// 去锯齿
selectBkgPaint.setColor(Color.parseColor("#f4f4f4"));// 颜色
selectBkgPaint.setTextSize(textSize); // 设置轴文字大小
// 选中之后 显示数据的画笔 //控制选中的点和选中点的数据
selectCirclePaint = new Paint();
selectCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE);
selectCirclePaint.setAntiAlias(true);// 去锯齿
selectCirclePaint.setColor(Color.parseColor("#CD00CD"));// 颜色
selectCirclePaint.setTextSize(40);
if (!selectData.equals("")) {// 点击某个刻度的时候 矩形区域颜色值改变(最高的一条线为top)
canvas.drawRect(rectF.left, YPoint - YLength + xyExtra, rectF.right, rectF.bottom,
selectBkgPaint);
}
// 设置Y轴
canvas.drawLine(xPoint, YPoint - YLength, xPoint, YPoint, linePaint);
// Y轴的箭头
canvas.drawLine(xPoint, YPoint - YLength, xPoint - 3, YPoint - YLength + 6, linePaint);
canvas.drawLine(xPoint, YPoint - YLength, xPoint + 3, YPoint - YLength + 6, linePaint);
// 设置X轴
canvas.drawLine(xPoint, YPoint, xPoint + xLength, YPoint, linePaint);
// X轴的箭头
canvas.drawLine(xPoint + xLength, YPoint, xPoint + xLength - 6, YPoint - 3, linePaint);
canvas.drawLine(xPoint + xLength, YPoint, xPoint + xLength - 6, YPoint + 3, linePaint);
canvas.drawText("日期", xPoint + xLength, YPoint + displacement * 3, textPaint); // 日期
canvas.drawText("金额", xPoint + displacement, YPoint - YLength, textPaint); // 金额
// Y轴线
for (int i = 0; i < 5; i++) {
// Y轴的每条线,X轴为xPoint-xPoint + xLength Y轴固定高度 YPoint - (i + 1) *
// YScale(根据圆点计算出的值)
canvas.drawLine(xPoint, YPoint - (i + 1) * YScale, xPoint + xLength, YPoint - (i + 1)
* YScale, linePaint); // 刻度
try {
// Y轴的刻度值,值为平均分配之后算出来的
canvas.drawText(String.valueOf(eachYLabel * (i + 1)), 5, YPoint - (i + 1) * YScale
+ 5, textPaint); // 文字
} catch (Exception e) {
}
}
canvas.drawText("0", 10, YPoint + displacement * 3, textPaint); // 文字
for (int i = 0; i < XLabel.length; i++) {
try {
// X轴的每条刻度线
canvas.drawLine(xPoint + (i + 1) * xScale, YPoint, xPoint + (i + 1) * xScale,
YPoint - displacement, linePaint);
// X轴显示的刻度值
if(i%2==0){
canvas.drawText(XLabel[i], xPoint + (i + 1) * xScale - halfXLabel, YPoint
+ displacement
* 3, textPaint); // 文字
}else{
canvas.drawText("", xPoint + (i + 1) * xScale - halfXLabel, YPoint
+ displacement
* 3, textPaint); // 文字
}
PointBean bean = new PointBean();
// 点击之后的矩形取悦
bean.rectF = new RectF(xPoint + i * xScale, 0, xPoint + (i + 1) * xScale, YPoint);
bean.dushu = Data[i];
bean.x = xPoint + (i + 1) * xScale - halfXLabel;
allpoint.add(bean);
if (i == 0) {
canvas.drawLine(xPoint + (i) * xScale, YPoint, xPoint + (i + 1) * xScale
- halfXLabel, YCoord(Data[i]), dataPaint);
canvas.drawCircle(xPoint, YPoint, circleSize, dataPaint);
canvas.drawCircle(xPoint + (i + 1) * xScale - halfXLabel, YCoord(Data[i]),
circleSize,
dataPaint);
} else {
canvas.drawLine(xPoint + (i) * xScale - halfXLabel, YCoord(Data[i - 1]), xPoint
+ (i + 1) * xScale - halfXLabel, YCoord(Data[i]), dataPaint);
canvas.drawCircle(xPoint + (i + 1) * xScale - halfXLabel, YCoord(Data[i]),
circleSize,
dataPaint);
}
} catch (Exception e) {
}
}
if (!selectData.equals("")) {
// 点击的时候,画出红点 和显示数据
canvas.drawCircle(selectX, YCoord(selectData), circleSize, selectCirclePaint);
canvas.drawText("金额:$" + selectData, selectX + displacement, YCoord(selectData)
- displacement+200, selectCirclePaint);
}
}
/**
* 计算Y坐标
*
* @param y0
* @return
*/
private float YCoord(String y0) // 计算绘制时的Y坐标,无数据时返回-999
{
float y;
try {
y = Float.parseFloat(y0);
} catch (Exception e) {
return -999; // 出错则返回-999
}
try {
// YScale/eachYLabel为比率 乘以y得到距离圆点的距离
return (float) (YPoint - YScale * y / eachYLabel);
} catch (Exception e) {
}
return y;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
for (int i = 0; i < allpoint.size(); i++) {
if (allpoint.get(i).rectF.contains(event.getX(), event.getY())) {
PointBean bean = allpoint.get(i);
selectX = bean.x;
selectData = bean.dushu;
rectF = bean.rectF;
postInvalidate();
}
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
if (xLength > screenWidth) {
int with = (int) (XLabel.length * xScale + xPoint + 25 * 2);
setMeasuredDimension(with, screenHeight);
} else {
setMeasuredDimension(screenWidth, screenHeight);
}
}
/**
* 计算Y轴坐标的最大值
*
* @param p
* @return
*/
public static float max(String[] p) {
float max = 0;
for (int i = 0; i < p.length; i++) {
if (Float.parseFloat(p[i]) - max > 0) {
max = Float.parseFloat(p[i]);
}
}
int length = (int) (max) / 20 + 1;// 为了取整数 比如最大值为39的时候 返回40
return length * 20;
}
}
1.2:自定义圆形ImageView,用于头像
package com.xxx.baseproject.view;
/**
* Created xuenan on 2015/10/14.
*/
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* 圆角ImageView
*圆形头像使用
* @author xuenan
*
*/
public class CustomImageView extends ImageView {
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomImageView(Context context) {
super(context);
init();
}
private final RectF roundRect = new RectF();
private float rect_adius = 90;
private final Paint maskPaint = new Paint();
private final Paint zonePaint = new Paint();
private void init() {
maskPaint.setAntiAlias(true);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//
zonePaint.setAntiAlias(true);
zonePaint.setColor(Color.WHITE);
//
float density = getResources().getDisplayMetrics().density;
rect_adius = rect_adius * density;
}
public void setRectAdius(float adius) {
rect_adius = adius;
invalidate();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
int w = getWidth();
int h = getHeight();
roundRect.set(0, 0, w, h);
}
@Override
public void draw(Canvas canvas) {
canvas.saveLayer(roundRect, zonePaint, Canvas.ALL_SAVE_FLAG);
canvas.drawRoundRect(roundRect, rect_adius, rect_adius, zonePaint);
//
canvas.saveLayer(roundRect, maskPaint, Canvas.ALL_SAVE_FLAG);
super.draw(canvas);
canvas.restore();
}
}
1.3:自定义不可滑动ViewPager,可以用于Fragment嵌套fragment的时候使用
/*
* @author http://blog.csdn.net/singwhatiwanna
*/
package com.xxx.baseproject.view;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* 自定义Viewpager禁止滑动
* */
public class CustomViewPager extends ViewPager {
private boolean isScrollable = false;
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (isScrollable == false) {
return false;
} else {
return super.onTouchEvent(ev);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isScrollable == false) {
return false;
} else {
return super.onInterceptTouchEvent(ev);
}
}
}
未完待续。。。
最后
以上就是陶醉老虎为你收集整理的完整Android项目搭建全过程的全部内容,希望文章能够帮你解决完整Android项目搭建全过程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复