我是靠谱客的博主 陶醉老虎,最近开发中收集的这篇文章主要介绍完整Android项目搭建全过程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

这篇博客也算是本人从事开发以来的一个总结,以前写博客是为了装逼,现在是为了成长,一个项目如果刚开始的框架没有搭建好,接下来的维护工作将变得异常困难,我们公司的按项目就是因为一开始的框架没有搭建好,只迭代了两个版本便维护不下去了,只能是请高人重新设计的框架,一切重新来过。

不同类型的项目对框架的要求自然不同,但是有一点是相同的,那就是,首先对基础语法进行封装,相应工具类、方法样式的封装,前期的封装可以避免后期项目无休止的重构代码,也就不会出现因频繁的改动需求导致代码大量冗余。

废话不多说,进入正题,要开始一个移动端项目搭建,一个最基本的前提条件就是要有完整的条理的产品需求,专业的产品原型图,这一切都是产品经理来做的,如果你们公司没有产品经理,那么你也就只能自求多福了,当然你有一个天天把就跟淘宝一样这句话挂在嘴边的二逼产品经理,你也只能自求多福了。
对一个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项目搭建全过程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部