0%

我想让一张图片在box里水平垂直居中显示,大小不固定,box的高度不固定,但有个最小值,这个需求应该可以用css实现,不需要动到强大的jQuery,但无奈技术太差,没解决,So,想到在载完图片后,用jQuery动态调整margin-top.

$(".original_preview img").load(function(){
    var original_preview_height=$(".original_preview").height();
    var preview_img_height=$(".original_preview img").height();
    var margin_top=(original_preview_height-preview_img_height)/2;
    $(".original_preview img").css("margin-top",margin_top);
});

在chrome中,仅仅有height:auto是不能实现一个box的高度自适应的,如果给这个box加个边框,会发现,即使这个box里有内容,它的上下边框还是并成一条线的,并没有实现高度自应用,还需要加一个属性overflow: auto; 。因为在Ubuntu下开发,只装了Chrome,不保证其他浏览器正常,也不打算兼容IE,相信只要大多数开发者抛弃邪恶的IE,用户自然会主动去升级。

之前写代码都没有很注意性能的问题,以后这方面会多关注一些。 如果要在ListView显示布局完全不同的Item,我之前的做法是在getView里先判断那个position的对象是哪一个类型,再相应的inflate对应的xml,但这样有个问题,就是没法复用convertView,因为可能会混乱。 今天发现其实Adapter有getItemViewType和getViewTypeCount方法,看名字就知道功能了,一个是获取该项的类型,另一个是获取类型的数量。 所以,使用很简单,第一步,在自定义的Adapter里继承这两个方法,并实现。getItemViewType返回的值不能是自定义的,必须从0开始增长。 第二步,在getView方法里,根据getItemViewType返回的类型,分别inflate对应的xml,如果convertView不为空,可以直接使用.另外,建议使用ViewHolder保存控件引用,使用convertView.setTag(holder)方法保存到convertView上,可以减少不必要的findViewById.

JDK自带了zip相关的api,但遗憾的是,如果zip文件中有包含中文名的文件,就报错无法处理,所以,我这里的例子并没有用jdk的api,而是用了apache的ant包。 apache ant下载地址: http://ant.apache.org/bindownload.cgi 把lib/ant.jar放到我们项目的构建路径中,只需要ant.jar。其实ant的zip API与jdk的高度相似,如果之前是用jdk的api写的,基本上只要更改顶部的import包就可以了

package common;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Enumeration;
import java.util.List;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

public class ZipUtils {
    public static void main(String[] args) throws Exception {
        unzipPSD("/media/share/material/file/temp/1eeb28ecb8e0d6f2.zip","/media/share/material/file/temp/");

    }

    /**
     * 解压zip,
     * 
     * @param zipFile 里面可以有多个psd文件,支持多级目录
     * @param targetPath 保存目录
     * @throws Exception 
     */
    public static void unzipPSD(String zipPath, String targetPath) throws Exception {

            ZipFile zipFile = new ZipFile(zipPath);
            Enumeration emu = zipFile.getEntries();
            int i = 0;
            while (emu.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) emu.nextElement();

                String fileName=entry.getName().toLowerCase();
                if(!fileName.startsWith("__macosx/")&&fileName.endsWith("psd"))
                {
                    //如果文件名没有以__macosx/开头,且以psd结尾,就是psd文件,解压,在mac下压缩的文件,会自动加上__macosx目录,但其实是没用的
                    BufferedInputStream bis = new BufferedInputStream(
                            zipFile.getInputStream(entry));
                    File file = new File(targetPath + System.currentTimeMillis()+".psd");
                    //一次读40K
                    int BUFFER=40960;
                    FileOutputStream fos = new FileOutputStream(file);
                    BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER);

                    int count;
                    byte data[] = new byte[BUFFER];
                    while ((count = bis.read(data, 0, BUFFER)) != -1) {
                        bos.write(data, 0, count);
                    }
                    bos.flush();
                    bos.close();
                    bis.close();
                }
            }
            zipFile.close();

    }

    /**
     * 压缩多个文件
     * @param zipPath
     * @param filePaths
     */
    public static void zipFiles(String zipPath,List filePaths)
    {
        try {
            BufferedInputStream origin = null;
            FileOutputStream dest = new FileOutputStream(zipPath);
            ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(
                    dest));
            int BUFFER=40960;
            byte data[] = new byte[BUFFER];

            for(String filePah:filePaths)
            {
                File file=new File(filePah);
                FileInputStream fi = new FileInputStream(file);
                origin = new BufferedInputStream(fi, BUFFER);
                ZipEntry entry = new ZipEntry(file.getName());
                out.putNextEntry(entry);
                int count;
                while ((count = origin.read(data, 0, BUFFER)) != -1) {
                    out.write(data, 0, count);
                }
                origin.close();
            }
            out.close();

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

}

其实,如果只是取缩略图,Java本身就自带了相关的API,不需要强大的ImageMagick,但是我的源图是PSD格式,Java默认是读不了的,有个java-psd-library开源项目,是纯java写的,经过测试,生成的图片全黑,放弃。最终选择了JMagick和ImageMagick的组合。做转换的是ImageMagick,Jmagick只是封闭的jni接口而已。 JMagick依赖ImageMagick,先装ImageMagick: ./configure make sudo make install sudo ldconfig /usr/local/lib 安装JMagick: autoconf ./configure --with-java-home=/home/fhp/Programs/jdk1.6.0_39 make all make install 配置参数需要加上jdk目录 复制生成的库到jre的lib目录,下面是64位的路径: cp /usr/local/lib/libJMagick.so /home/fhp/Programs/jdk1.6.0_39/jre/lib/amd64 在程序中调用(先把JMagick的src下的源代码拷到项目中):

package com.pocketdigi.psd;

import java.awt.Dimension;
import java.io.IOException;

import magick.ImageInfo;
import magick.MagickImage;

public class Test {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
         //取得原文件
        try {            
            ImageInfo sourceInfo=new ImageInfo( "/media/share/material/seal_social_icons.psd" );
            MagickImage image = new MagickImage(sourceInfo  );
            //获取图片的宽高
            Dimension dim=image.getDimension();
            MagickImage small =  image.scaleImage(dim.width,dim.height);
            small.setFileName( "/media/share/material/seal_social_icons.jpg");
            small.writeImage( new ImageInfo() );
 
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        
    }

}

环境 ubuntu 12.04桌面版,mysql 5.6.12 mysql需要使用cmake编译,所以,先安装cmake sudo apt-get install cmake 配置编译参数: cmake -DCMAKE_INSTALL_PREFIX=/home/fhp/server/mysql -DSYSCONFDIR=/home/fhp/server/mysql -DMYSQL_DATADIR=/home/fhp/server/mysql/data -DMYSQL_TCP_PORT=3306 -DMYSQL_UNIX_ADDR=/tmp/mysqld.sock -DEXTRA_CHARSETS=all 我一般把自己编译装的软件都放到/home下,这是个独立的分区,不会因为系统崩溃重装系统而丢失数据,至于为什么其他博主,教材都把软件装到/usr,/opt下,配置文件放/etc,不太清楚,搞不明白这样有什么优势,或者只是因为某篇教程是这么干的,大家抄抄成了习惯。 如果配置报错,可能需要安装libssl-dev,libncurses5-dev sudo apt-get install libssl-dev libncurses5-dev 第一次配置报错,第二次配置前,需要删除源码目录下的CMakeCache.txt,再配置。 编译,安装 make make install 初始化数据库: chmod 755 scripts/mysql_install_db scripts/mysql_install_db --basedir=/home/fhp/server/mysql/ --datadir=/home/fhp/server/mysql/data/ 复制启动脚本,开机自启: sudo cp support-files/mysql.server /etc/init.d/mysql sudo chmod 755 /etc/init.d/mysql chkconfig mysql on 手动启动,更改root密码: sudo /etc/init.d/mysql start /home/fhp/server/mysql/bin/mysqladmin -u root password 'new-password'

Mongodb官方提供的Java驱动,保存与读取,需要的者是DBObject对象,这是一个接口,实现put,get等方法,跟map类似,如果我们要直接把普通的java对象保存到mongodb,就需要先转换成DBObject对象,或者直接实现DBObject接口,操作起来相当复杂。还好,monodb驱动带了把json转换成DBObject对象的功能,加上Google的Gson,就可以实现把普通的对象保存到mongodb中。如果要从mogodb中读出对象,反过来操作即可,但有一点需要注意的是,mongodb的文档没有固定的字段,所以用Gson转换,可能因为各个文档属性不同,转出的对象属性都是空的,要确保在插入时都是插入同一个类的对象。 下面的例子是把User对象插入到Mongodb中,并读出来 User.java:

package com.mongo;

public class User {
    String name;
    int age;
    Oid _id;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    /**
     * Mongodb会自动生成ObjectId
     * @author fhp
     *
     */
    public class Oid{
        String $oid;
        public String get$oid() {
            return $oid;
        }

        public void set$oid(String $oid) {
            this.$oid = $oid;
        }
        
    }
}

Main.java:

package com.mongo;

import java.net.UnknownHostException;

import com.google.gson.Gson;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.util.JSON;

public class Main {

    /**
     * @param args
     * @throws UnknownHostException 
     */
    public static void main(String[] args) throws UnknownHostException {
        // TODO Auto-generated method stub
        MongoClient mongoClient = new MongoClient();

        DB psdoc = mongoClient.getDB("psdoc");
        DBCollection user=psdoc.getCollection("user");
        
        User u1=new User();
        u1.setAge(20);
        u1.setName("ssss");
        Gson gson=new Gson();
        //转换成json字符串,再转换成DBObject对象
        DBObject dbObject = (DBObject) JSON.parse(gson.toJson(u1));
        //插入数据库
        user.insert(dbObject);
        
        DBCursor cursor=user.find();
        while(cursor.hasNext())
        {
        	DBObject obj=cursor.next();
        	//反转
        	User u=gson.fromJson(obj.toString(), User.class);
        	System.out.println(u.name);
        }
    }

}

为了方便,可以直接把Gson整合进驱动里,直接修改驱动的源代码 com.mongodb.DBCollection.java: 新增方法:

    /**
     * 把普通的对象写入数据库
     * 
     * @param obj
     * @return
     */
    public WriteResult insert(Object obj) {
        Gson gson = new Gson();
        DBObject dbObject = (DBObject) JSON.parse(gson.toJson(obj));
        gson=null;
        return insert(dbObject);
    }

com.mongodb.DBCursor.java: 新增方法

    /**
     * 从数据库读出对象
     * @param obj
     * @param clazz
     * @return
     */
    public  T nextObj(Class clazz) {
        _checkType( CursorType.ITERATOR );
        Gson gson=new Gson();
        T u=gson.fromJson(_next().toString(), clazz);
gson=null;
        return u;
    }

修改后的调用方法: Main.java:

package com.mongo;

import java.net.UnknownHostException;

import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.MongoClient;

public class Main {

    /**
     * @param args
     * @throws UnknownHostException 
     */
    public static void main(String[] args) throws UnknownHostException {
        // TODO Auto-generated method stub
        MongoClient mongoClient = new MongoClient();

        DB psdoc = mongoClient.getDB("psdoc");
        DBCollection user=psdoc.getCollection("user");
        
        User u1=new User();
        u1.setAge(20);
        u1.setName("ssss");
        //直接插入对象
        user.insert(u1);
        DBCursor cursor=user.find();
        while(cursor.hasNext())
        {
        	//传入类参数,反回该类对象
        	User u=cursor.nextObj(User.class);
        	System.out.println(u.name);
        }
    }

}

iptux应该linux下是目前最好用的局域网聊天客户端了,与win下的飞鸽,飞秋完全兼容,但是有一BUG,不知道算不算BUG,也许是开发人员故意这样设计。当调整窗口大小时,iptux会自动缩小,小到只能看到图标,看不到主机名。解决方法: 拉大窗口,在自动缩小到合适的位置时,速度关闭客户端,重启,就能保持那个大小了。

主要用到了strtotime函数,功能强大,支持相对日期

//计算本月第一天和最后一天
$today=date("Y-m-d");
//这个不需要解释吧,直接把第一天设为1号
$firstday = date('Y-m-01', strtotime($today)); 
//这个语法以前还真没见过,php manual http://www.php.net/manual/zh/datetime.formats.relative.php
$lastday = date('Y-m-d', strtotime("$firstday +1 month -1 day")); 

echo $firstday."<br/>";
echo $lastday;

Android默认的进度条,如果是圆型的,是不能显示进度的,只是在转圈圈,而基于官方的ProgressBar自定义,也只能换那个圈圈的图片而已,无法实现展示进度。下图是要实现的效果: circleProgressbar 其实原理也很简单,定义一个类继承View,在onDraw方法里画圆即可. CircleProgressBar:

package com.pocketdigi.curcleprogressbar.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;

public class CircleProgressBar extends View {
    private int maxProgress = 100;
    private int progress = 30;
    private int progressStrokeWidth = 4;
    //画圆所在的距形区域
    RectF oval;
    Paint paint;
    public CircleProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO 自动生成的构造函数存根
        oval = new RectF();
        paint = new Paint();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO 自动生成的方法存根
        super.onDraw(canvas);
        int width = this.getWidth();
        int height = this.getHeight();
        
        if(width!=height)
        {
            int min=Math.min(width, height);
            width=min;
            height=min;
        }
        
        paint.setAntiAlias(true); // 设置画笔为抗锯齿
        paint.setColor(Color.WHITE); // 设置画笔颜色
        canvas.drawColor(Color.TRANSPARENT); // 白色背景
        paint.setStrokeWidth(progressStrokeWidth); //线宽
        paint.setStyle(Style.STROKE);

        oval.left = progressStrokeWidth / 2; // 左上角x
        oval.top = progressStrokeWidth / 2; // 左上角y
        oval.right = width - progressStrokeWidth / 2; // 左下角x
        oval.bottom = height - progressStrokeWidth / 2; // 右下角y

        canvas.drawArc(oval, -90, 360, false, paint); // 绘制白色圆圈,即进度条背景
        paint.setColor(Color.rgb(0x57, 0x87, 0xb6));
        canvas.drawArc(oval, -90, ((float) progress / maxProgress) * 360, false, paint); // 绘制进度圆弧,这里是蓝色
        
        paint.setStrokeWidth(1);
        String text = progress + "%";
        int textHeight = height / 4;
        paint.setTextSize(textHeight);
        int textWidth = (int) paint.measureText(text, 0, text.length());
        paint.setStyle(Style.FILL);
        canvas.drawText(text, width / 2 - textWidth / 2, height / 2 +textHeight/2, paint);

    }
    
    
    
    public int getMaxProgress() {
        return maxProgress;
    }

    public void setMaxProgress(int maxProgress) {
        this.maxProgress = maxProgress;
    }

    public void setProgress(int progress) {
        this.progress = progress;
        this.invalidate();
    }

    /**
     * 非UI线程调用
     */
    public void setProgressNotInUiThread(int progress) {
        this.progress = progress;
        this.postInvalidate();
    }
}

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ccc"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >


    <com.pocketdigi.curcleprogressbar.view.CircleProgressBar
        android:id="@+id/circleProgressbar"
        android:layout_width="60dp"
        android:layout_height="60dp" />

</RelativeLayout>

MainActivity.java:

package com.pocketdigi.circleprogressbar;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;

import com.pocketdigi.curcleprogressbar.view.CircleProgressBar;

public class MainActivity extends Activity {

    CircleProgressBar progressBar;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        progressBar=(CircleProgressBar)findViewById(R.id.circleProgressbar);
        new Thread()
        {
            public void run()
            {
                int i=0;
                while(i<=100)
                {
                    progressBar.setProgressNotInUiThread(i);
                    i++;
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        // TODO 自动生成的 catch 块
                        e.printStackTrace();
                    }
                }
            
            }
        }.start();
        
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

虽然代码很简单,还是照顾一下新人,上源码包: [download id=”41” format=”1”]