2018年8月

前言

最近在学习自定义控件的绘制,今天来学习一下Android Canvas——画布的相关api。


drawXXX系列

  • canvas.drawArc——画扇形

    drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)
    drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)

通过所规定的矩形(见第一个方法的RectF),以矩形的中心点为坐标原点绘制此扇形。

startAngle 开始旋转的位置 (0°在坐标轴的三点钟方向)
sweepAngle 需要旋转多少度 (大于360,则画出一圈)
useCenter 是否使用中心点,true时起点和终点都会连接矩形的中心点;false时起点和终点会直接连接起来。
如:

RectF rectF=new RectF(200,200,400,400);
canvas.drawArc(rectF,0,270,true,paint);          //画一个扇形 角度顺时针转动

从0°开始顺时针旋转270°的扇形

  • canvas.drawCircle——绘制圆形

    drawCircle(float cx, float cy, float radius, Paint paint)

cx、cy 圆的圆心坐标
radius 圆的半径
如:

canvas.drawCircle(400,400,200,paint);

**绘制一个圆心为(400,400),半径为200的圆形。
注:当画笔设置了 StrokeWidth 时,圆的半径=内圆的半径+StrokeWidth/2**

  • canvas.drawBitmap——绘制图像

    drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)

matrix 构建的矩阵作用于将要画出的位图
如:

Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
Matrix matrix=new Matrix();
matrix.postTranslate(100,100);
matrix.postRotate(45);
canvas.drawBitmap(bitmap,matrix,paint);
drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)

src 规定绘制bitmap上src区域的部分图像
dst 规定绘制的区域大小(图像填满整个区域)
如:

Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
Rect src=new Rect(50,50,100,100);
Rect dst=new Rect(100,100,200,200);
canvas.drawBitmap(bitmap,src,dst,paint);

drawBitmap(Bitmap bitmap, float left, float top, Paint paint)

left 绘制的起点(左上角)距离左边的距离
top 绘制的起点(左上角)距离顶部的距离

drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, Paint paint) 

用于网格扭曲,水波等的绘制。

  • canvas.drawColor,drawRGB,drawARGB——在整个绘制区域统一涂上指定的颜色

    canvas.drawColor(Color.GREEN);
    canvas.drawRGB(100,150,200);
    canvas.drawARGB(100,100,150,200);
    该方法一般用于给区域添加一个半透明的遮罩层。

  • canvas.drawPoint——绘制圆点

    drawPoint(float x, float y, Paint paint)
    x,y 点的坐标

注:点的大小可通过paint.setStrokeWidth(30)设置,点的形状可通过paint.setStrokeCap(Paint.Cap.ROUND)设置。

  • canvas.drawPoints——绘制一组圆点

    drawPoints(float[] pts, Paint paint)
    drawPoints(float[] pts, int offset, int count,Paint paint)
    float[] pts 绘制圆点的坐标数组(数组每相邻两位形成一个坐标)

offset 从数组的第几个位置开始计算坐标
count 需要绘制的圆点个数
如:

float[] points = {0, 0, 50, 50, 50, 100, 100, 50, 100, 100, 150, 50, 150, 100};
canvas.drawPoints(points,paint);
  • canvas.drawOval——绘制椭圆

    drawOval(float left, float top, float right, float bottom, Paint paint)
    drawOval(RectF rect, Paint paint)

4个参数分别是上下左右的边界点

  • canvas.drawLine——绘制线

    drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
    startX, startY, stopX, stopY 分别是线的起点和终点坐标。

  • canvas.drawLines——绘制一组线

    drawLines(float[] pts, int offset, int count, Paint paint)
    drawLines(float[] pts, Paint paint)
    与上述的绘制一组圆点同理~

  • canvas.drawRoundRect——绘制带圆角的矩形

    drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)
    drawRoundRect(RectF rect, float rx, float ry, Paint paint)
    与绘制矩形同理~

前言

最近在学jQuery,今天来讲讲如何在web上利用jQuery动态生成列表,并对其每一个item做监听。


获取列表并对其进行遍历

一般的业务逻辑都是通过网络请求从后台中获取一个列表,在java中一般使用list存储。在js中就是一个数组了。

$.ajax({
        type:"POST",
        data:{userId:userId},
        url:server+"/order/getOrderByUserId",
        success:function (result) {
            if(result.code==200){
                createOrders(result.resultMap.list);
            }else{
                console.log(result);
                // showCommonModal(result.message);
            }
        },
        error:function (e) {
            alert("服务器异常,请稍后重试...");
        }
    });

这里我使用的是Ajax请求,result.resultMap.list就是我们所需要的列表集合了。

$.each(list,function (index,value) {
  ...
});

通过jQuery的$.each()就可以实现集合的遍历效果了,第一个参数list就是我们刚刚提到的列表集合,第二个参数传入一个函数,index是这个集合的下标(即0、1、2、3...),value是index对应的对象值。


通过集合遍历动态生成html

有了上述的遍历基础就可以正式通过遍历动态生成列表了。

  • 首先我们需要在html中编写一个div作为整个个动态生成列表的容器:

    <div class="content"></div>

  • 然后我们需要在遍历前创建一个变量:

    var item="";

  • 遍历的时候通过往该变量添加html:

     items+='<div class="container-fluid bg-white mt-2 item" id='+value.id+'>'+
                '<div class="row pt-2">'+
                    '<div class="col-8">' +
                        '<i class="fa fa-calendar mx-2" aria-hidden="true"></i><p class="d-inline-block date">'+value.createTime+'</p>'+
                    '</div>' +
                    '<div class="col-4"><p class="text-warning text-right align-items-center state">'+stateTxt+'</p></div>'+
                    '</div>' +
            '<div class="border-bottom"></div>' +
            '<p class="text-dark mt-2 books">'+value.bookName+'</p>'+
            '<div class="border-bottom"></div>' +
                '<div class="row mt-2">' +
                    '<div class="col-4 offset-8 text-right">合计:<i class="fa fa-jpy" aria-hidden="true"></i><p class="d-inline-block price">'+value.totalPrice+'</p></div>'+
                '</div>' +
            '</div>';
    
  • 最后通过append添加到之前定义的容器div中:

    $(".content").append(items);
    注:我们可以通过在div中添加自定义属性来存放我们在item监听中可能用到的数据:

items+='<div class="container-fluid bg-white mt-2 item" id='+value.id+'>'+

上述的id='+value.id+'就是一个自定义属性,当我们需要取出使用时可以通过以下写法来获取刚刚存进去的值:

var id=$(this).attr("id");

这样就完成了整个列表的动态生成了,这里我做的是一个订单列表,整个函数方法如下:

function createOrders(orders) {
var items="";
$.each(orders,function (index,value) {
    var stateTxt;
    if(value.state == "1"){
        stateTxt="待付款"
    }else if(value.state == "2"){
        stateTxt="待收货"
    }else if(value.state == "3"){
        stateTxt="已收货"
    }
    items+='<div class="container-fluid bg-white mt-2 item" id='+value.id+'>'+
                '<div class="row pt-2">'+
                    '<div class="col-8">' +
                        '<i class="fa fa-calendar mx-2" aria-hidden="true"></i><p class="d-inline-block date">'+value.createTime+'</p>'+
                    '</div>' +
                    '<div class="col-4"><p class="text-warning text-right align-items-center state">'+stateTxt+'</p></div>'+
                    '</div>' +
            '<div class="border-bottom"></div>' +
            '<p class="text-dark mt-2 books">'+value.bookName+'</p>'+
            '<div class="border-bottom"></div>' +
                '<div class="row mt-2">' +
                    '<div class="col-4 offset-8 text-right">合计:<i class="fa fa-jpy" aria-hidden="true"></i><p class="d-inline-block price">'+value.totalPrice+'</p></div>'+
                '</div>' +
            '</div>';
});
$(".content").append(items);
}

如何监听每个item的事件

$(".content").on('click','.item',function () {
   ...
})

我们需要通过注册上述那个列表容器的div也就是这里的.content的on事件来实现item事件的监听。on函数里面第一个参数是需要监听的事件,比如click点击事件;第二个参数是需要监听的位置,比如整个item(这里定义了每个item的div为.item),第三个参数就是监听是的函数回调了。


最后

最后看看效果图

前言

这篇文章总结一下一些代码优化的问题,本文出自代码优化


String字符串优化

最常见的例子就是当你要频繁操作一个字符串时,使用StringBuffer代替String。
还比如:使用int数组而不是Integer数组。
避免创建短命的临时对象,减少对象的创建就能减少垃圾收集,进而减少对用户体验的影响。


ListView优化

  • Item布局,层级越少越好,使用hierarchyview工具查看优化。
  • 复用convertView
  • 使用ViewHolder
  • item中有图片时,异步加载
  • 快速滑动时,不加载图片
  • item中有图片时,应对图片进行适当压缩
  • 实现数据的分页加载

减少不必要的全局变量

尽量避免static成员变量引用资源耗费过多的实例,比如Context。
因为Context的引用超过它本身的生命周期,会导致Context泄漏。所以尽量使用Application这种Context类型。
你可以通过调用Context.getApplicationContext()或 Activity.getApplication()轻松得到Application对象。


Cursor(游标)回收

Cursor是Android查询数据后得到的一个管理数据集合的类,在使用结束以后。应该保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理。并且Android明显是倾向于编程者手动的将Cursor close掉,因为在源代码中我们发现,如果等到垃圾回收器来回收时,会给用户以错误提示。


Receiver(接收器)回收

调用registerReceiver()后未调用unregisterReceiver().
当我们Activity中使用了registerReceiver()方法注册了BroadcastReceiver,一定要在Activity的生命周期内调用unregisterReceiver()方法取消注册
也就是说registerReceiver()和unregisterReceiver()方法一定要成对出现,通常我们可以重写Activity的onDestory()方法,在onDestory里进行unregisterReceiver操作


Stream/File(流/文件)回收

主要针对各种流,文件资源等等如:
InputStream/OutputStream,SQLiteOpenHelper,SQLiteDatabase,Cursor,文件,I/O,Bitmap图片等操作等都应该记得显示关闭。


避免内部Getters/Setters

在Android中,虚方法调用的代价比直接字段访问高昂许多。通常根据面向对象语言的实践,在公共接口中使用Getters和Setters是有道理的,但在一个字段经常被访问的类中宜采用直接访问。
for循环
访问成员变量比访问本地变量慢得多,如下面一段代码:

for(int i =0; i < this.mCount; i++)  {}  

永远不要在for的第二个条件中调用任何方法,如下面一段代码:

for(int i =0; i < this.getCount(); i++) {}  

对上面两个例子最好改为:

int count = this.mCount; / int count = this.getCount();  
for(int i =0; i < count; i++)  {}