Markdown小技巧
Markdown删除线和插入视频和音乐的方法
Markdown删除线和插入视频和音乐的方法
1 | actionBar.hide(); |

1 | SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this,R.array.action_list,android.R.layout.simple_spinner_dropdown_item); |
1 | OnNavigationListener mOnNavigationListener = new OnNavigationListener() { |
1 | actionBar = getActionBar(); |

1 |
|
1 | getMenuInflater().inflate(R.menu.options, menu); |
1 | public class MyActionProvider extends ActionProvider{ |
1 | listView.setOnScrollListener(new OnScrollListener(){ |
Android 3.0(Honeycomb)之前,Android支持两种动画tween animation,frame animation,3.0引入了一个新的动画————property animation。可通过NineOldAndroids实现对低版本的支持。
给出两个关键帧,通过一些算法将给定属性值在给定的时间内在两个关键帧间渐变。View Animation只能应用于View对象,而且只支持一部分属性,如支持缩放旋转不支持背景颜色的改变。
ViewAnimation就是一系列View形状的变换,如大小的缩放、透明度的改变、位置的改变,动画的定义既可以用代码定义也可以使用XML定义。
用XML定义的动画在/res/anim/文件夹内,XML文件的根元素可以是
1 | Animation hyperspaceJumpAnimation=AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump); |
Drawable Animation(Frame Animation)帧动画,通过一系列Drawable依次显示来模拟动画
1 | <animation-list xmlns:android="http://schemas.android.com/apk/res/android" |
必须以
1 | imageView.setBackgroundResource(R.drawable.drawable_anim); |
属性动画
这面的动画该对象在40ms在x轴移动40pixel。默认10ms刷新一次,这个对象移动了4次,每次移动40/4=10pixel

也可以改变属性值的改变方法,设置不同的interpolation,比如下图运动的速度逐渐增大后再逐渐减小

下图显示了与上述动画相关的关键对象

ValueAnimator表示一个动画,包含动画的开始值、结束值、持续时间等属性
ValueAnimator封装了一个TimeInterpolator,定义了属性在开始值与结束值之间的插值计算方法
ValueAnimator还封装了一个TypeAnimator,根据开始值、结束值与TimeIniterpolator计算得到的值计算出属性值
ValueAnimator根据动画已进行的时间跟动画总时间(duration)的比计算出一个时间因子(0~1),然后根据TimeInterpolator计算出另一个因子,最后TypeAnimator通过这个因子计算出属性值,如上例中10ms时:
首先计算出时间因子,即经过的时间百分比:t=10ms/40ms=0.25
经插值计算(inteplator)后的插值因子:大约为0.15,上述例子中用了AccelerateDecelerateInterpolator,计算公式为(input即为时间因子):
1 | (Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; |
最后根据TypeEvaluator计算出在10ms时的属性值:0.15*(40-0)=6pixel。上例中TypeEvaluator为FloatEvaluator,计算方法为 :
1 | public Float evaluate(float fraction, Number startValue, Number endValue) { |
ValueAnimator包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。应用Property Animation有两个步聚:
ValuAnimiator只完成了第一步工作,如果要完成第二步,需要实现ValueAnimator.onUpdateListener接口,这个接口只有一个函数onAnimationUpdate(),在这个函数中会传入ValueAnimator对象做为参数,通过这个ValueAnimator对象的getAnimatedValue()函数可以得到当前的属性值如:
1 | ValueAnimator animation = ValueAnimator.ofFloat(0f,1f); |
onAnimationUpdate()通过监听这个事件的值更新时执行的操作,对ValueAnimation一般要监听此事件执行相应的动作,不然则没有意义。ObjectAnimator中会自动更新属性,如无必要不必监听。在函数中会传递一个ValueAnimator参数,通过此参数的getAnimatedValue()取得当前动画属性值。
AnimatorListener用于监听动画的执行过程,有如下一些回调方法
1 | onAnimationStart() |
可以继承AnimatorListenerAdapter而不是实现AnimatorListener接口来简化操作,这个类对AnimatorListener中的函数都定义了一个空函数体,这样我们就只用定义想监听的事件而不用实现每个函数却只定义一空函数体。
1 | ObjectAnimator oa = ObjectAnimator.ofFloat(tv,"alpha",0f,1f); |
继承自ValueAnimator,要指定一个对象即带对象的一个属性,当属性值计算完成时,自动设置为该对象的相应属性。使用ObjectAnimator,需要满足下面条件
1 | tv=(TextView)findViewById(R.id.textview1); |
View对象属性:
AnimationSet提供一个把多个动画组合成一个组合的机制,并可以设置组中动画的时序关系。
1 | // anim1播发完,同时播发anim2、anim3、anim4,之后播发anim5 |
根据属性的开始值、结束值与TimeInterpolation计算出的计算因子计算出当前时间的属性值,Android提供方了以下几个evalutor:
1 | public class FloatEvaluator implements TypeEvaluator { |
Time interplator定义了属性值变化的方式,在Property Animation中是TimeInterplator,在View Animation中是Interplator,这两个是一样的,在3.0之前只有Interplator,3.0之后实现代码转移至了TimeInterplator。Interplator继承自TimeInterplator,内部没有任何其他代码。
ViewGroup中的子元素可以通过setVisibility使其Visible、Invisible或Gone,当有子元素可见性改变时(VISIBLE、GONE),可以向其应用动画,通过LayoutTransition类应用此类动画:
1 | transition.setAnimator(LayoutTransition.DISAPPEARING,customDisappearingAnim); |
通过setAnimator应用动画,第一个参数表示应用环境,第二个参数是一个动画,环境可以是以下4种:
1 | mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30); |
此函数设置动画延迟时间,参数分别为类型与时间。
keyFrame是一个时间/值对,通过它可以定义一个在特定时间的特定状态,即关键帧,而且在两个keyFrame之间可以定义不同的Interpolator,就像多个动画的拼接,第一个动画的结束点是第二个动画的开始点,KeyFrame是一个抽象类,要通过ofInt()、ofFloat()、ofObject()获得适当的KeyFrame,然后通过PropertyValuesHolder.ofKeyframe获得PropertyValueHolder对象,如下例子:
1 | Keyframe kf0 = Keyframe.ofInt(0, 400); |
上述代码设置了btn对象的width属性值:
1 | ObjectAnimator oa = ObjectAnimator.ofInt(btn2,"width",400,200,400,100,500); |
true或false| 属性 | 说明 |
|---|---|
| android:layout_centerHrizontal | 水平居中 |
| android:layout_centerVertical | 垂直居中 |
| android:layout_centerInparent | 相对于父元素完全居中 |
| android:layout_alignParentBottom | 贴紧父元素的下边缘 |
| android:layout_alignParentLeft | 贴紧父元素的左边缘 |
| android:layout_alignParentRight | 贴紧父元素的右边缘 |
| android:layout_alignParentTop | 贴紧父元素的上边缘 |
| android:layout_alignWithParentIfMissing | 如果对应的兄弟元素找不到的话就以父元素做参照物 |
“@id/id-name”| 属性 | 说明 |
|---|---|
| android:layout_below | 在某元素的下方 |
| android:layout_above | 在某元素的的上方 |
| android:layout_toLeftOf | 在某元素的左边 |
| android:layout_toRightOf | 在某元素的右边 |
| android:layout_alignTop | 本元素的上边缘和某元素的的上边缘对齐 |
| android:layout_alignLeft | 本元素的左边缘和某元素的的左边缘对齐 |
| android:layout_alignBottom | 本元素的下边缘和某元素的的下边缘对齐 |
| android:layout_alignRight | 本元素的右边缘和某元素的的右边缘对齐 |
| 属性 | 说明 |
|---|---|
| android:layout_marginBottom | 离某元素底边缘的距离 |
| android:layout_marginLeft | 离某元素左边缘的距离 |
| android:layout_marginRight | 离某元素右边缘的距离 |
| android:layout_marginTop | 离某元素上边缘的距离 |
Handler直接继承Object,一个Handler允许发送和处理一个Message或者Runnable对象,并且会关联到主线程的MessageQueue中。没个Handler具有一个单独的线程,并且关联到一个消息对象的线程,就是说一个Handler有一个固定的消息队列。
Handler主要有两个作用:
Handler把压入消息队列分为Post和sendMessage:
对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。
在Handler中,关于Post方式的方法有:
Message是一个final类,所有不可继承,Message封装了线程中传递的消息,对于一般的数据Message提供了getData()和setData()方法来获取与设置数据,其中操作的数据是一个Bundle对象,这个Bundle对象提供了一系列的getXxx()和setXxx()方法用于传递基本数据类型的键值对。对于复杂的数据类型,Bundle提供了两个方法,专门用来传递对象,但是这两个方法也有相应的限制,需要实现特定的接口。
对于Message对象,一般不推介直接使用构造方法创建,而是使用Message.obtain()这个静态方法或者Handler.obtai()获取,此两者都是从消息池中获取,消息的数量是有上限的,为10个。
向Handler发送消息一般分两种:一种是根据Handler对象,使用handler.sendMessage()方法来发送消息,一种是根据Handle获取Message,如handler.obtai()或者Message.obtain(handler),该Message会有一个属性Target,调用sendToTarget()方法,会发送到创建时的Handler中去。
Handler中,与Message发送消息相关的方法有:
/res/values/ids.xml
ids.xml是区别于R文件的一种设置控件ID的方式。使用示例如下:
1 | <Button |
1 | <resources> |
3.在调用控件时
1 | Button bn = new Button(context); |
使用ids.xml的优点如下
用于包装数组
// 在arrays.xml中定义
1 | <resources> |
在Java中调用
1 | CharSequence[] items = this.getResources().getStringArray(R.array.reboot_item); |
attrs.xml用于设定自定义属性
res/values文件夹下定义一个attrs.xml文件1 |
|
1 | public class MyView extends View { |
1 |
|
1 |
|
1 |
|

AVOSCloud提供了一个完整的后端解决方案
在 AVOS Cloud 平台注册后,您创建的每个应用程序都有其自己的应用程序 ID 和 Key, 在您的应用程序中将凭此 ID 和 Key 使用 AVOS Cloud SDK。您的账户可以创建容纳多个应用程序,这是非常方便和有用的。即使您只有一个应用程序,也可以使用不同的版本进行测试和生产。
AVOS Cloud存储的数据是建立在AVObject基础上,每个AVObject包含键(key)-值(value)对的JSON兼容的数据。
键必须是字母、数字的字符串,值可以是字符串、数字、布尔值、JSON数组和AVObject对象等。每个AVObject有一个类名,你可以用它来区分各种不同的数据。
1 | AVObject myObj = new AVObject("MyObject"); |
使用AVQuery通过ObjectID检索到一个完整的AVObject
1 | AVQuery<AVObject> query = new AVQuery<AVObject>("MyObject"); |
获取AVObject对象,然后进行修改值后保存数据
1 | AVQuery<AVObject> query = new AVQuery<AVObject>("MyObject"); |
1 | myObj.increment("value1"); |
设置fetchWhenSave属性为true会使更新后,AVObject获得最新值
1 | myObj.setFetchWhenSave(true); |
从服务器删除对象
1 | myObj.deleteInBackground(); |
对象可以与其他对象相联系,就像数据库中的主外键关系一样,数据表A的某一个字段是数据表B的外键,只有表B中存在的数据才插入进A中的字段。
1 | AVObject myWeibo = new AVObject("Post"); |
默认情况下,获取一个对象的时候,关联的AVObject不会被获取,这些对象的值无法获取,直到调用fetch
1 | myConment.getAVObject("post").fetchIfNeededInBackground(new GetCallback<AVObject>() { |
使用AVRelation来建模多对多关系。
比如一个User喜欢很多Post,可以用getRelation方法保存一个用户喜欢的用户的Post集合。```java
AVUser user = AVUser.getCurrentUser();
AVRelation
relation.add(post);
user.saveInBackground();
// 从AVRelation中移除一个Post
relation.remove(post)
1 | 默认情况,处于关系的对象集合不会被下载,可以通过`getQuery`方法返回的`AVQuery`对象,使用它的findInBackground方法来获取Post链表 |
支持的数据类型有String、Int、Boolean、AVObject,同时支持java.util.Date、byte[]、JSONObject、JSONArray数据类型。
先创建一个AVQuery对象,然后通过添加不同的条件,使用findInBackground方法结合FindCallback回调类来查询与条件匹配的AVObject数据,使用whereEqualTo方法来添加条件值
1 | AVQuery<AVObject> query = new AVQuery<AVObject>("MyObject"); |
想查询匹配几个不同值的数据,如:要查询”steve”、”chard”、”jack”三个人的成绩,可以使用whereContainedIn方法来实现,排除可以使用whereNotContainedIn方法
1 | String[] names = {"steve","chard","jack"}; |
使用whereMatches方法可以使用任何正确的正则表达式来检索匹配的值
1 | // 比较name字段的值是以大写字母和数字开头 |
查询字符串中包含“XX“内容,可用如下方法:
1 | // 查询playerName字段的值中包含“ste“字的数据 |
如果key对应的值是一个数组,可以查询key的数组包含了数字2的所有对象
1 | query.whereEqualTo("arrayKey",2); |
同样,你可以查询出 Key 的数组同时包含了 2,3 和 4 的所有对象:
1 | //查找出所有arrayKey对应的数组同时包含了数字2,3,4的所有对象。 |
使用 whereStartsWith 方法来限制字符串的值以另一个字符串开头。非常类似 MySQL 的 LIKE 查询,这样的查询会走索引,因此对于大数据集也一样高效:
1 | //查找出所有username以avos开头的用户 |
query使用count替代find可以统计多少个对象满足查询
1 | query.countInBackgroud(new CountCallback(){ |
Swift的String类型和Foundation的NSString类进行了无缝桥接,所有NSString API都可以调用Swift的String类型的值
字符串字面量是由双引号(“”)包裹的具有固定顺序的文本字符集
字符串字面量可以包含以下特殊字符:
1 | var emptyString = "" |
可以通过分配一个变量来对字符串进行修改,或者分配一个常量保证其不被修改
String类型进行常量、变量赋值操作或在函数\方法中传递,会进行拷贝,是值传递
Swift的String类型表示特定序列的character类型值的集合
1 | for character in "Hello world"} |
可以表明Character类型来创建字符常量或者变量
1 | let a:Character = "1" |
通过调用全局的countElement函数,并将字符串作为参数传递,可以获取字符串的字符数量
1 | let str = "I have a word" |
使用+相加就可以连接字符串
使用+=可以讲一个字符串加上另一个字符串存到原有的字符串上
字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式
1 | \(Double(3) * 2.5) // "7.5" |
Swift 提供了三种方式来比较字符串的值:字符串相等、前缀相等和后缀相等。
1 | let str = "一样样的" |
通过字符串的uppercaseString和lowercaseString属性来方位大写/小写版本的字符串
Unicode是一个国际标准,用于文本的编码和表示。
每一个字符都可以被Unicode解释成一个或多个unicode标量。字符的unicode标量是一个唯一的21位数字,例如U+0061表示小写的拉丁字母a
当Unicode字符串被写进文本文件或其他存储结构当中,这些unicode标量将会按照Unicode定义的集中格式之一进行编码,其中包括UTF-8(以8位代码单元进行编码)和UTF-16(以16位代码单元进行编码)
Swift提供了几种不同的方法来访问字符串的Unicode
UTF8View类型的属性,是无符号8位(UInt)值的集合,同理utf16属性是UTF16View类型的属性1 | let dogString "Dog!" |
unocodeScalars属性为UnicodeScalarView类型的属性,是UnicodeScalar的集合,UnicodeScalar是21位的 Unicode 代码点。
1 | for scale in dogString.unicodeScalars { |
集合类型(Collection Types)
数组使用有序列表存储同一类型的多个值,相同的值可以多次出现在一个数组的不同位置中
在Swift中。数据值在被存储进入某个数组之前类型必须明确,方法是通过显示的类型标注或类型推断,Swift的数组是类型安全的,并且它包含的类型必须明确,这点和NSArray和NSMutableArray很不同。
数组遵循Array<SomeType>这样的形式,其中SomeType是这个数组中唯一允许存在的数据类型。也可以使用像SomeType[]这样的简单语法。
形如[value1,value2,value3]
1 | var names:String[] = ["joy","jack"] |
变量被声明为字符串类型的数组
由于Swift的类型推断机制,也可以这样写
1 | var names = ["jay","jack"] |
可以通过数组的方法和属性来访问和修改数组,或者下表语法。还可以使用数组的只读属性count来获取数组中的数据数量,使用isEmpty属性可以检测数组是否为空,使用append方法在数组后面添加新的数据项,也可以使用(+=)添加单个数据项或者拥有相同数据类型的数组
也可以通过索引获取数组项
1 | var names = ["joy","jack"] |
调用insert(atIndex:)可以再在指定位置插入数据,removeAtIndex方法可以移除数组中的某一项,removeLast方法可以移除最后一项
使用for-in循环来遍历所有数组中的数据项
1 | for item in shoppingList{ |
也可以使用全局enumerate函数来进行数组遍历
1 | for (index,value) in enumerate(shoppingList) { |
1 | var someInts = Int[]() |
字典是一种存储多个相同类型的值的容器,没个值都关联唯一的键,键作为字典中的这个值数据的标识符。字典的数据项没有具体的顺序,需要通过键访问数据。
与Objective-C中的NSDictionary和NSMutableDictionary类可以使用任何类型的对象做键和值不同,Swift在某个特定字典中可以存储的键和值必须提前定义,方法是通过显式标注或者类型推断
Swift的字典可以使用Dictionary<KeyType,ValueType>定义,其中keyType是键的数据类型,ValueType是值的数据类型。keyType的唯一限制是可哈希的,这样可以保证它的唯一性,所有Swift的基本类型(String,Int,Double和Bool)都是可哈希的,未关联的枚举成员也是可哈希的。
[key1:value1,key2:value2,key3:value3]可以创建字典
1 | var airports:Dictionary<String,String> = ["TYO":"Tokyo","DUB":"Dublin"] |
使用下标语法或者字典的方法属性可以读取字典,只读属性count来获取字典的数据项的数量
也可以使用下标法添加新的数据项updateValue(forkey:)方法可以设置或更新特定键对应的值,根据键值是否存在判断。该函数会返回包含一个字典值类型的可选值
1 | airports["LHR"] = "London Heathrow" // 添加数据项 |
使用下标法也可以访问对应键的值,如果不存在,返回nil,通过下标法设置某键的值为nil,也可以删除数据项,也可以使用removeValueForKey方法移除
1 | if let removedValue = airports.removeValueForKey("DUB"){ |
使用for-in语法便可遍历,每一个字典的数据项都由(key,value)元组形式返回
1 | for (airportCode,airportName) in airport { |
也可以访问它的keys和values属性检索一个字典的键或者值
1 | for airportCode in airports.keys { |
创建空字典
1 | var nameOfIntegers = Dictionary<Int,String>() |
如果数组或字典设置为变量,那么它的数据项是可变的,设置为常量,那么它的大小是不可变的,数据在首次设定之后便不能改变。不同的是,数组的大小不能改变,但是可以改变它的值。
控制流
for循环用作按照指定的次数多次执行一系列语句。Swift提供了两种for循环形式:
for-in用来遍历一个区间(range),序列(sequence),集合(collection),系列(progression)里面多有的元素for-condition-increment)语句,用来重复执行一系列语句知道达到特定条件,一般通过在每次循环完成后增加计数器的值来实现。1 | // index不需要声明 |
如果不需要知道区间每一项的值,可以使用下划线(_)替代变量名忽略对值的访问
1 | for _ in 1...9{ |
1 | for var index = 0; index < 3;++index{ |
下面是一般情况下这种循环方式的格式:
for
initialization;condition;increment{
statements
}
while循环运行一系列语句直到条件变成false。这类循环适合使用在第一次迭代前迭代次数未知的情况下。Swift 提供两种while循环形式:
1 | while condition{ |
Swift提供两种类型的条件语句:if语句和switch语句。通常,当条件较为简单且可能的情况很少时,使用if语句。而switch语句更适用于条件较复杂、可能情况较多且需要用到模式匹配(pattern-matching)的情境。
if语句最简单的形式就是只包含一个条件,当且仅当该条件为true时,才执行相关代码:
1 | if true { |
switch语句会尝试把某个值与若干个模式(pattern)进行匹配。根据第一个匹配成功的模式,switch语句会执行对应的代码。
1 | witch some value to consider { |
swift不存在隐藏的贯穿,即不需要break,执行完也会推出,同时swift还支持区间匹配
1 | switch count{ |
元组匹配
1 | var count = (1,3) |
case分支的模式允许将匹配的值绑定到一个临时的常量或变量,这些变量或常量在该case分支里就可以被引用————这种行为被称为值绑定
1 | let point = (2,0) |
case分支模式可以使用where语句来判断额外的条件
1 | let point = (1,0) |
控制转移语句改变你代码的执行顺序,通过它你可以实现代码的跳转。Swift有四种控制转移语句。- continue
continue语句告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。
break语句会立刻结束整个控制流的执行。
Swift不存在C语言中switch语句的贯穿行为,要实现需要使用fallthrouth
1 | switch count{ |
环体和switch代码块两者都可以使用break语句来提前结束整个方法体,通过带标签的语句可以指定想要终止哪个循环或者switch代码块,如果有许多嵌套的循环体,也可以实现continue指定跳转
1 | label name:while condition{ |
1 | loop:while count != 100{ |
函数(Functions)
1 | func sayHello(personName:String) -> String{ |
1 | func fun(start: Int,end: Int) -> Int { |
1 | func say() -> String{ |
1 | func sayGoodbye(personName: String){ |
1 | func count(str:String) -> (vowels: Int, consonants: Int,others: Int) { |
在函数定义时定义的参数为局部参数名,只能在函数体中使用
类似于Objective-C的函数命名
1 | func join(string s1:String,toString s2:String) -> String{ |
上面的方法需要为参数提供外部参数名和内部参数名,可以通过# 简写,将外部参数名和内部参数名等同起来
1 | func join(# string:String,# toString:String) -> String{ |
为参数提供一个初始值,调用时,缺省可以忽略并使用默认值
1 | func join(str1 String,str2 String = "world") -> String{ |
1 | func add (numbers: Double...) -> Double { |
函数参数默认是常量,在函数体中更改参数值将会导致编译错误,如果参数定义为变量就可以当做参数的副本来使用
1 | // 用来右对齐输入的字符串到一个长的输出字符串中。左侧空余的地方用指定的填充字符填充 |
一个输入输出参数时,在参数定义前加inout关键字。一个输入输出参数有传入函数的值,这个值被函数修改,然后被传出函数,替换原来的值。当传入的参数作为输入输出参数时,需要在参数前加&符,表示这个值可以被函数修改。
1 | func swap (inout a:Int,inout b:Int){ |
每个函数都有种特定的函数类型,由函数的参数类型和返回类型组成。() -> ()表示没用参数,返回Void,在Swift中,Void与空元组是一样的
使用函数名来给另一个函数赋值
1 | var fun2:(Int,Int) -> Int = fun1 |
1 | var mathFunction:(Int,Int) -> Int = addTwoInts |
1 | func printMathResult(matchFunction:(Int,Int) -> Int,a:Int,b:Int){ |
1 | func chooseStepFunction(backwards:Bool) -> (Int) -> Int { |
闭包
闭包之自包含的函数代码块,可以在代码中传递和使用,与Objective-C的blocks相似
闭包可以捕获和存储其所在上下文任意常量和变量的引用。
全局和嵌套函数也是特殊的闭包,闭包采取如下三种形式:
闭包表达式是一种利用简洁语法构建内联闭包的方式,闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。
闭包表带式语法一般形式:
1 | { (parameters) -> returnType in |
Swift标准库提供了sort函数,会根据基于输出类型排序的闭包函数将已知类型数组的值进行排序,返回一个与原数组大小相同的新数组,并排序完成。