SVG动画——Android 5.0新特性介绍(2)

先放点motivation

(GIF图点开,看动画)

test要实现这个布局很简单,用FrameLayout加一个ImageView并设置一个图片,再在FrameLayout上放一个RelativeLayout,背景用t这个矢量图。布局文件如下:

<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:padding="20dp"
                tools:context=".MainActivity">
    <FrameLayout
        android:id="@+id/card_view"
        android:layout_centerInParent="true"
        android:layout_width="260dp"
        android:layout_height="430dp"
        >

        <ImageView
            android:id="@+id/img"
            android:src="@drawable/p1"
            android:scaleType="centerCrop"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
        <RelativeLayout
            android:id="@+id/card_content"
            android:background="@drawable/animate_rect"
            android:layout_width="match_parent"
            android:layout_height="320dp"
            android:padding="15dp">
            <TextView
                android:id="@+id/title"
                android:textColor="#03A9F4"
                android:textSize="25sp"
                android:layout_marginTop="6dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Vector card"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"/>
            <TextView
                android:id="@+id/tv_content"
                android:gravity="center"
                android:layout_marginTop="18dp"
                android:layout_below="@id/title"
                android:text="Lorem ipsum dolor sit amet, Duis aute irure dolor in reprehenderit sunt in culpa quilaborum. in voluptate velit esse cillum dolore eu fugiat nulla ."
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                />


        </RelativeLayout>

    </FrameLayout>
</RelativeLayout>

怎么让它动起来呢?其实很简单,只要修改SVG图中的pathData就行,也就是从梯形变成一个长方形。原来的pathData的坐标和要变化的新坐标如图所示,t

 

SVG文件内容:sharp_rect.xml

注意,我们把path加了一个name=”sharp_rect”,这是做动画效果是要指定这部分,所以需要给个独一无二的name作为id.

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="180dp"
        android:height="320dp"
        android:viewportWidth="180"
        android:viewportHeight="400">

    <path
        android:name="sharp_rect"
        android:fillColor="#000000"
        android:pathData="M 180,230 L 0,320 0,0 180,0 z" />
</vector>

下面做animate-vector drawable:

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/sharp_rect">
    <target
        android:animation="@animator/to_rect"
        android:name="sharp_rect"/>
</animated-vector>

在animated-vector里填入android:drawable=”@drawable/sharp_rect”,这是指定要产生动画的SVG。target里是需要动画的对象,这里我们的对象就是前面那个叫sharp_rect的梯形,所以name里填上它,然后animation填的是对应的动画文件。

动画用的是ObjectAnimator做的,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
                android:duration="330"
                android:interpolator="@android:interpolator/decelerate_cubic"
                android:propertyName="pathData"
                android:valueType="pathType"
                android:valueFrom="M 180,230 L 0,320 0,0 180,0 z"
                android:valueTo="M 180,75 L 0,75 0,0 180,0 z" />

值得注意的是,我们要从梯形变成矩形,就是对pathData进行修改,也就是propertyName要填入pathData,valueType是pathType,valueFrom是原来的路径(也就是梯形的路径),最终变成的效果是valueTo(矩形的路径)。这里有个要注意的地方,如果要进行path的变换,里面的点数必须要一样!

 

Ok了大功告成,最后只要把ImageView的src改成animate_rect就行了,并设置触发函数就行了

 final ImageView play = (ImageView)findViewById(R.id.icon_play);
        play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Drawable drawable = play.getDrawable();
                if ( drawable instanceof Animatable){
                    ((Animatable) drawable).start();
                }
            }
        });

注意,上面我这种方法不是Android SVG推荐的用法,SVG动画尺寸应该尽可能的小,和简单,因为每次动画都会先把这些path先计算绘成Bitmap,然后上传texture到GPU,如果SVG太大意味着生成更大的Bitmap,占更多内存,消耗更多时间.Google的推荐是把SVG用于图标(icon)和按钮(Button),只有需要的时候才修改Vector的属性(比如alpha,width,height),因为如果SVG不用于动画,android会把这个图生成一个Cache来节省时间,如果SVG动画这个Cache就没有用了。如果要用SVG动画,请确保它“短小精悍”(Short and sweet)。

下面还有一些SVG动画的例子:

(GIF图,点开看)

35ed6362d41a2a3e5a64d3bb8ed16033

Demo源代码: https://github.com/qianlvable/VectorCard

参考:

DevBytes: Android Vector Graphics (youtube视频,需翻墙)

VectorDrawables – Styling Android 系列

Transitioning to Infinity (一个很厉害的法国人,不过他的程序都是用C#写的,本文的BlueTooth的动画来源于这个博客)

SVG图像——Android 5.0新特性介绍(1)

本文将介绍什么是SVG图像,及如何在Android中使用SVG及一些简单的SVG动画。

什么是SVG?

SVG的全称是Scalable Vector Graphics,叫可缩放矢量图形。它和位图(Bitmap)相对,SVG不会像位图一样因为缩放而让图片质量下降。下面这个图片展示了SVG和位图的区别,左边的位图在放大后出现了锯齿,而右边的SVG任然清晰。svg_cp

 

为什么要使用SVG?

  • 节约空间,使用方便

因为SVG可以任意缩放而图像任保持清晰的特点,且在android里SVG是在运行时才进行渲染的,它会根据屏幕的dpi自动缩放到合适的大小,所以我们仅仅用一个SVG文件就可以代替多个不同dpi的drawable了!下面给出一个用SVG的android logo代替多种dpi的drawable的占用空间大小对比.svg_size_cp

  • 用XML就可以写出一些简单的动画。下面会给例子

如何在Android中使用?

  • 把普通SVG图片转成Android可用格式:

有两种方法,手动改一下原始SVG的格式,或者用一个自动转换的工具(Android SVG to VectorDrawable)

下面展示一下,这个图像的SVG文件内容t

<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 180 400" width="180px" height="320" preserveAspectRatio="none">
    <path d="M 180,230 L 0,320 0,0 180,0 z" fill="#000000"/>
</svg>

path是画出这个矢量图所需的笔画路径,这里就是移植到android所需要的关键部分。下面来看转换成android能用SVG图内容,这里我将重点讲解

sharp_rect.xml

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="180dp"
        android:height="320dp"
        android:viewportWidth="180"
        android:viewportHeight="400">

    <path
        android:name="sharp_rect"
        android:fillColor="#000000"
        android:pathData="M 180,230 L 0,320 0,0 180,0 z" />
</vector>

注意到和普通SVG图内容不同地方在与viewBox那变成了viewportWidth,viewportHeight,viewport就相当于画这个SVG的画布大小。width和height是规定这个SVG图像最终的显示大小的,一般用dp表示。第二个不同是有一个普通SVG里的fill到android里要变成fillColor,这里就是SVG图像填充的颜色。第三点不同是,普通SVG的path的数据是d开头的标签,在android里要写成pathData。综上所述,只要把viewBox的大小改成viewport的大小,把填充颜色的fill改成fillColor,把Path中的d,改成pathData就行了。

还有最后一个问题pathData中的那些奇怪的东西是啥?数字是在viewport中的坐标点,M代表move to(把画笔移动到),L是Line(划线),Z是封闭path.(更多参考

我们可以通过上面的变动手动把普通SVG转成android用的VectorDrawable,或者我们可以用这个网站自动完成转换 http://inloop.github.io/svg2android/

 

  • 显示

这个SVG就直接就是Drawable直接用就好:

<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:padding="20dp"
                tools:context=".MainActivity">
         <ImageView
            android:src="@drawable/sharp_rect"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />        
</RelativeLayout>

 

下一篇文章将介绍一个使用SVG图像动画的例子: )

控制随机——产生不同概率的事件

本文将对产生不同概率的方法和高斯分布的使用做总结。

在实际情况中我们有时候不光只是要随机,有时候还要不同概率大小情况的下的随机事件,比如发生A事件的几率是30%,B事件是40%,等等.实现它有多种方法,最只觉得想法的就是在一个数组里填充几种元素,通过控制各元素的个数来控制概率,比如我要A事件发生的概率为40%,B事件发生的概率为60%.可以造一个长度为10的boolean数组,里面4个设置为true,另外6个位false,然后随机从里面抽一个出来,true就发生事件A,false就发生事件B。代码如下:

boolean array = new boolean[10];
array[0] = true;
...
array[3] = true;

if (array[random(0,10)]){
    triggerA();
}else{
    triggerB();
}

这个方法的弊端是当有多样元素的填充很麻烦,并且浪费不必要的空间。

另一个办法,这个办法更简单:

比如我想要一个概率为60%的A事件,发生概率为20%的B事件,20%的C事件代码如下:

float p = 0.6;
float rand = random(1); // return a number betwenn 0~1
if( rand < p){
    triggerA();
}else if ( p < rand < 0.8){
    triggerB();
} else {
    triggerC();
}

 

有时候我们需要概率随着一定规律变化,比如从1~100中选择数字,要求实现数字越大选中的概率越大,可以用二次随机的方法(这种方法也叫Monte Carlo method)。

下面的例子返回一个0~1的数,概率大小的变化和数字大小成正比 p = value

float montecarlo(){
    while(true){
        float r1 = random(1);
        float p = r1;
        float r2 = random(1);
        if( r2 < p){
            return r1;
        }
    }
}

可以通过修改上面代码很容易得出概率和数字成正比的随机函数的方法.

高斯分布又叫正态分布(本文后续全部使用正态分布这个叫法),这是生活中出现很多的随机分布现象,比如人的身高,财富情况都是正太分布.下面我介绍一下如何把正态分布用于随机中.

要使用正态分布,首先要明白两个参数,mean 和 deviation:

 正态分布mean是中值,也就是数据最集中的那里.deviation是偏差的意思.也就是和中值偏差的大小.有了这两个值就可以用来对高斯分布进行操纵了,偏差越小意味着数据越集中在中值处,偏差越大意味着数据越分散.那么到底在程序中要怎么用正态分布呢?下面用Java里的Random.nextGaussian()为例,它会返回一个mean为0,deviation为1的随机数字.我们做一个在窗口中大小为600的画布上用正态分布画彩色球小的程序:

import java.util.Random;
Random gen;

int r = 0;
int g = 0;
int b = 0;
float x = 0;
float y = 0;

void setup(){
    // 设置屏幕大小为600
  size(600,600);
  gen = new Random();
}
// 这里是循环执行的部分
void draw(){
  float num = (float) gen.nextGaussian();
  float standardDeviation = 40;  // 偏差设置为80
  float mean = 300;             // 中间值设为300,屏幕的中中心
  
  // 随机产生小球的颜色
  r = int(random(255));
  g = int(random(255));
  b = int(random(255));
  fill(r,g,b);
  
  // 这里就是使用状态分布的地方了 偏差 * 正太分布产生的随机数 + 偏差
  // 产生小球的坐标
  x = standardDeviation * num + mean;
  
  num = (float) gen.nextGaussian();
  y = standardDeviation * num + mean;
  // 画球
  ellipse(x,y,15,15);
  
}

ball1

 

这里是偏差为40时的运行截图,注意到因为偏差比较小小球都集中在屏幕中心,也就是中值附近.

当偏差为80时运行截图为:

ball2

 

注意到偏差较大的时候,求不在是特别集中于中值附近,成较分散状.

 

 

Git rebase合并多个commit

有时候为了修改一个功能,对一个功能进行了多次琐碎commit,想把这些琐碎的commit整合成一个commit就可以使用rebase进行操作。比如,我现在有4个分支分别如下:

  • fix issue CAT-1061
  • fix issue CAT-1061
  • fix issue CAT-1061
  • removed unused variable

现在我想把这个4个commit合成一个commit。

第一步,打开你的项目的git bash界面。

输入如下命令:

git rebase -i HEAD~4

命令说明:i代表interactive的意思,就理解为对它的操作吧。HEAD是指向当前版本的文件头指针,HEAD~4指的是对从HEAD开始的前4个commit进行操作。

第二步,指向完上面的命令以后,会弹出一个文本编辑器(git默认是vim或者其他的文本编辑器)如下图

pick

pick代表支持rebase整合的分支,如果把那个pick移除掉这个commit就会不见。这里我们的目标是合并所以,把后三条的pick改成squash(挤压的意思)就可以达成我们压缩commit的目的,结果如下:

squash

 

然后保存并退出就会开始rebase了。

Tips:如果是用vim,在退出编辑模式(按esc)然后就是进入了command mode,此时输入命令:wq就是保存和退出的意思。

Android studio添加.so文件

在用到百度sdk和一些第三方库的时候会有.so文件的添加,而官方一般只给出了Eclipse的添加方法,国内的教程也是停留在比较老的gradle版本的.国外的一些教程也是对于老版本的gradle添加的一些奇技淫巧(workaround),在gradle 0.73的时候已经对这个有支持了,在stackoverflow看到了方法和大家分享一下

  • 确定你gradle版本在0.7.3 以上(如果下载的最新的Android studio就不用看了)
  • 在你的工程下创建如下文件 (x86 那是对不同版本的cpu的支持,一般添加armeabi就行了)

  • 点开app里的build.gradle

对应刚才建立的文件夹添加:

   productFlavors {
        x86 {
            ndk {
                abiFilter "x86"
            }
        }
        arm {
            ndk {
                abiFilters "armeabi-v7a", "armeabi"
            }
        }

    }

 

完成!

Fragment简单上手

刚开始接触android开发,我们知道一个界面就是一个Activity.那Fragment拿来干什么呢?我们先从名字上看,Fragment的中文意思是”碎片”,我们就可以简单理解Fragment可以存放一个个我们界面的小碎布,我们可以拼接起多个小碎布在一个平面里(一个Activity里多个Fragment).或者我们可以更加简单(不是很准确)的理解,我们就把Fragment当Activity使用,不同就是Fragment可以动态改变.

Fragment说明
一个Activity里两个Fragment的示例

简单实用方法(这里只说动态的添加方法,不说静态):

  • 首先,我们得有一个容器来放Fragment的布局

建一个xml(叫main.xml),作为放Fragment的容器这个标签叫FrameLayout

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

这个就像是一个空白的白板可以放入其他的布局

  • 我们要有个继承自Fragment的类(这就相当于Activity),这里填充我们要添加的新界面的xml布局文件
public class FragmentExample extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view =  inflater.inflate(R.layout.要填充的layout名字, container, false);
        return  view;
    }
}

这里我们只Override一个onCreateView方法,里面填充我们页面的layout.(就是当这个Fragment的view创建的时候做的事情)类似Activity的onCreate.(注意Fragment也有自己的生命周期也有onCreate方法,具体请看google文档).

  •  每个Fragment都要住(host)在一个Activity里,里面调用一个FragmentManager,来管理Fragment
  public class OneActivity extends FragmentActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 找到放container的layout
        setContentView(R.layout.main);
        // 这里是用来support class 如果你目标是3.0以上就可以直接用FragmentManager就好了
        FragmentManager manager = getSupportFragmentManager();
        Fragment fragment = manager.findFragmentById(R.id.frame_container);
        
        // 可能fragment已经存在了(和生命周期有关)
        if (fragment == null){
            // 创建刚才建立的Fragment
            fragment = new ExampleFragment();
            // 把它添加给Fragment Manager
            manager.beginTransaction()
                .add(R.id.frame_container,fragment)
                .commit();
        }
    }
  }

 

这样这个Activity里就填充了刚才new的Fragment了.

用一个新的Fragment代替当前的Fragment

// 把新的Fragment替换到当前的fragment_container里
transaction.replace(R.id.fragment_container, newFragment);
// 加到statck里让用户按back的时候还可以回来
transaction.addToBackStack(null);

// 添加到FragmentManger 里
transaction.commit();

 

快速下载Android SDK更新

用SDK manger更新非常慢,不妨用迅雷下载.

步骤:

  1. 先在sdk manger里选中要更新下载的东西
  2. 打开sdk的目录,在里面会有一个叫temp的文件夹,里面会有刚选中下载的文件
  3. 复制它的名字;在迅雷里新建下载链接 格式: “https://dl-ssl.google.com/android/repository/刚才复制的文件名(注意后缀也要有)”
  4. 下载完成后复制进刚才temp这个文件夹内,然后再点install就马上开始安装了!

 

快速简单上手Bootstrap

本文假设你就懂一点点html,高手请跳过。

Bootstrap是什么

Bootstrap是几个牛逼闪闪的twitter工程师为减少web开发重复工作量的一个框架,大白话就是他们做好了所有css的装饰,你只要调用对应的标签(class name),就可以写出一个漂亮的网站,跟着下面的例子,我将带你快速建立一个页面。

开始使用

在这里下好bootstrap,解压

http://getbootstrap.com/2.3.2/getting-started.html   

在解压好的根目录里面创建新建的页面,这里例子为index.html

注意:为了显示中文不是乱码,请确认的你文本编辑器保存的格式是UTF-8 !

<!DOCTYPE html>
<html>
<head lang="zh-CN">
<meta charset="utf-8">
<title>网站标题</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link href="css/bootstrap.css" rel="stylesheet" media="screen">
</head>
<body>

<script src="http://code.jquery.com/jquery.js"></script>
<script src="js/bootstrap.min.js"></script>
</body>
</html>

<link href=”css/bootstrap.css” rel=”stylesheet” media=”screen”>这一句是调用bootstrap的样式表,这样就可以用bootstrap了!

这两句请确保为body的最后两行:

<script src="http://code.jquery.com/jquery.js"></script>
<script src="js/bootstrap.min.js"></script>

 

接下来我们要用内置的框架实现以下的页面布局:

布局

用container标签,存放内容

container它可以把内容居中,然后设置好与其他距离的padding.相当于一个放内容的容器.

把下面片段加入<body></body>里:

<div class="container">
</div>

  • 添加网站标题

在container里添加如下代码:

<h1>第一次用Bootstrap</h1>

在浏览器可以看到出现标题了,但是还没有到激动的时刻.

  • 添加导航栏

在Bootstrap里面只要打class名为navbar就可以制作导航栏了,导航栏有几种形式(固定,浮动,顶部,底部 etc),详情见官网文档。导航栏里的内容在<div class=navbar-inner></div>里添加,每一个选项放在<ul></ul>标签里即可。把下面代码放到建立的container里面,在刚才建立的标题下面

<div class="navbar navbar-static-top" id="nav">
      <div class="navbar-inner">
        <div class="container">
          <ul class="nav">
              <li class="active"><a href="#">Home</a></li>
              <li><a href="#">label1</a><li>
              <li><a href="#">label2</a><li>
              <li><a href="#">label3</a><li>      
          </ul>        
        </div>     
      </div>
 </div>

一个导航栏就做好了,保存文件,在浏览器刷新一下试试!

  • 放入宣传内容区域(我自己起的名字),还有按钮

Bootstrap把这里的class叫 hero-unit,把下面的内容继续放进container里面放在navbar下面:

<div class="hero-unit">
    <h1>宣传区域</h1>

    <p>我们要通过bootstrap做一个非常碉堡的产品页面。这将非常有趣。</p>

    <a href="#" class="btn btn-large btn-info">我们开始!</a>
</div>

class btn可以让它以按钮的样式显示,btn-info是绿色的按钮,更多设置看官网文档。

打开浏览器看看效果!

  • 加入左侧导航列

根据前面设想的布局图,左边放左导航栏,右边内容区域。这要把一个container的宽度,分为两个不均等的小块。下面看看用bootstrap怎么实现。Bootstrap里布局用网格(grid system)建立每一个小模块,以一格为最小单位计数来计量宽度,最大有12格,长度如下:

1

在本例里,我们选择宽度为3和宽度为8的两列,建立方式如下:

就像画表格一样我们先建立一个class为row(行)的div,然后里面两个不同长度的格子来划分这个row,spanN N代表网格数N取值为1~12。这里span3我们放入左导航列(表示导航栏的宽度为3个格)

 <div class="row">

         <div class="span3">

         </div>
         <div class="span8">

         </div>
</div>
把下面代码加入,刚才建立的<div class=”span3″>中:
<ul class="nav nav-list">
    <li class="nav-header">关于我们</li>
    <li class="active"><a href="#">主页</a></li>
    <li><a href="#">我们的客户</a></li>
    <li><a href="#">我们的服务</a></li>
    <li><a href="#">联系我们</a></li>
    <li class="nav-header">品牌赞助商</li>
    <li><a href="#">Google</a></li>
    <li><a href="#">Yahoo!</a></li>
    <li><a href="#">Bing</a></li>
    <li><a href="#">Microsoft</a></li>
</ul>

下面再span8里加入文章内容:(网章内容随机摘自网络)

<h3>我们开始</h3>

<p>“之所以我们的生活里充满了对生活的抱怨和吐槽,那是因为我们的生活里没什么大事儿。倘若有大事情等着我们去解决,怎么会有那闲工夫抱怨?”</p>

<p> 
我大学时只很努力的学习英语,别的什么事儿都没干,尽管我的水平并没有北大清华的同学那么好,但是我努力向他们靠近。他们考什么我就考什么,他
们学什么我不知道,我就把图书馆的所有英语教材和书籍都借出来挨个看。毕业聚会的时候,一个同学翻着白眼跟我说:“你有什么啊,不就是英语好点才有个好工
作吗?”哦,是的,就因为我英语好点,所以我有个好工作,而你毕业的时候什么都没有。我不是骄傲,而是想说,只要你努力,只要你肯下功夫每天变好一点点,
尽管你未来可能还是什么都没有,但有哪怕一丁点优势就不会饿死人,这世上最不会贬值的投资就是为自己努力。</p>

<h3>Coursera 今天宣布又有13家院校加入</h3>

<p>这13个院校来自11个国家,包括中国、丹麦、英国、意大利、荷兰跟俄罗斯等。</p>

<p>根据 Coursera 最新提供的数据图表显示, Coursera 上面的课程老师平均每个人带了7,204个学生。课程视频共被浏览了3亿多次。
</p>

刷新看看应该很棒吧!

添加底部的三个小版块

我们想在最下面加入三个小介绍注脚,把一个row分成3个span4等宽的区域。实现代码如下:

<div class="row">

<div class="span4">

        <h4 class="muted text-center">客户群</h4>

        <p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.</p>

        <a href="#" class="btn"><i class="icon-user"></i> 客户信息</a>

    </div>

    <div class="span4">

        <h4 class="muted text-center">了解雇员</h4>

        <p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.</p>

        <a href="#" class="btn btn-success"><i class="icon-star icon-white"></i> 雇员信息</a>

    </div>

    <div class="span4">

        <h4 class="muted text-center">找到我们</h4>

        <p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.</p>

        <a href="#" class="btn btn-info">连线</a>

    </div>

</div>

贴入前面的代码,刷新你的浏览器,Awesome!发现这次按钮里有了图标。

n3

看代码多了<i></i>的标签,bootstrap里面提供各种漂亮的这种图标,有黑白两色的,更多选项看官网文档.

添加footer

我们把我们的copyright放在这里:

<hr />
<div class="footer">
© 2013 built with Bootstrap @小伙伴
</div>

大功告成!

QQ截图20131024151605

剩下的去看官方文档吧!

如果想看中文版点这里 中文文档

幸福不在下一站

 以前特别喜欢One more struggle,and you will be free这句话,总可以感觉那个让人期盼的自由终就在不远的地方,只要手再伸远点,步再跨大点…..幸福和自由好像都在下一个台阶。可能你又过这样的感觉,考完高考你就轻松了,到大学又是工作了就轻松了,到工作又变成了退休就轻松了,好像幸福和自由永远都在前面,我们努力的奔向那个看似很美好的明天。

061293230328202_change_quyl0c73_b但是问题在于,每次到达一个阶梯的幸福满足感是短暂的,又要开始奔向下一个台阶了 。所以这句座右铭应该改一下变成,One more struggle,and I am free.理解为我是自由的,我在struggle。struggle本身就是一种快乐和自由的方式,在为了一个还不太清晰的明天而努力,为了一个看似幼稚的梦想,我在针扎我在努力同时我也是自由的。就像这样YOUNG AND FREE !

内蒙古沙漠之行