2014年12月15日 星期一
Material Design I : Floating Action Button (FAB)
自從Google再Lollipop(5.0)推出後,終於記得順便幫Android穿上漂亮的衣服,那就是 Material Design(MD)最重要的使命,不論是設計的元素、語言跟配色都有了屬於自己的Guildline。
對Android Developer而言,則是遵守官方規矩,就可以自己做出"有點"美感APP,官方BLOG還貼心的準備Check list給開發者(這表示幾乎都有附上source code)。而我們公司的產品也順著這班MD的風潮導入了許多元素,讓原本很iOS的APP找回了自己應有的面貌:> 這篇文章介紹其中一個導入的widget : Floating Action Button(FAB)
仿間有一大堆自製的牌子, 以下條列使用心得
https://github.com/makovkastar/FloatingActionButton
評論 : 最多star,多做了show/hide的animation,但用在5.0以下的Device會怪怪的(可能是我的project設定有問題)(這是我發的issue ticket),所以最後沒採用這套。
https://github.com/futuresimple/android-floating-action-button
評論: 它是fork上面那個的專案,不過它多做了sub-menu的功能(有點像Path的小紅點, 這也是MD其中一種元素),但沒有包裝show/hide的animation,最後我採用這套,因為他沒有上面的issue(神奇),最後我把上面animation的code搬到這個專案之中,搞定。
2014年10月11日 星期六
Paper.js : The Swiss Army Knife of Vector Graphics Scripting
Frontend的發展總是迅速,一堆超酷的Framework、Library總覺得永遠學不完;今天要介紹的Paper.JS大概又是讓我讚嘆已久的Library;還記得兩年前的HackDay,那時候的作品為了要呈現夢幻的感覺,用了Box2Djs及Canvas湊出了泡泡漂移的感覺,那時候寫起來特別吃力,因為Box2D的官方文件很簡陋,而且對於Html的Support也很粗淺,沒辦法它只是負責運算物理特效,所以Html的Event全部都要自己來!
今天看到了Paper.js的範例CandyCrash,有種相見恨晚的感覺,Framework的完整性超高,除了沒有物理運算以外,但呈現的效果已經比當初好的太多,而且可以有更多的延展性。
Brackets : a IDE for JavaScript, HTML and CSS
對開發者而言有幾點很棒的好處讓我也想使用它:
1. Auto Refresh : 裡面叫做Live Preview,也就是以後不用狂按Save-Reload,還可以安裝Static Preview的套件,就可以迅速架設一個Local的網站供其他人測試
2. 完整的文件提示 : 隨時按Cmd+K就可以看Html及Css屬性的文件
3. Color Picker
4. Image Preview
...
看來最近如果想玩Frontend的東西都會用它了吧!
Canvas coordinate system
最近加新功能的時,碰到一個在Canvas上座標系統認知上有所不同的地方;一般我們會用 Canvas.drawBitmap(Bitmap, 10, 10, Paint)把一張圖畫在(0,0)的位置,當然這個(0,0)不預期是整個device的(0,0),而是根據View最後被擺放的位置,例如某View被Layout在(100, 100),而Canvas.drawBitmap(Bitmap, 10, 10, Paint)則會畫在螢幕(110,110)的地方。
到目前為止都沒有錯誤,但如果translation的方式是用Matrix,而你的code可能會變成
Matrix matrix = new Matrix();
matrix.postTranslate(10, 10);
canvas.setMatrix(matrix);
Canvas.drawBitmap(Bitmap, matrix, Paint);
此時畫出來的結果就還是會在(10, 10)。原本猜想是忘記apply原本canvas的matrix所致,所以改成
Matrix matrix = new Matrix(canvas.getMatrix());
matrix.postTranslate(10, 10);
canvas.setMatrix(matrix);
Canvas.drawBitmap(Bitmap, matrix, Paint);
結果還是(10,10)!結果不小心喵到有Method叫Canvas.concat()。後來改成:
Matrix matrix = new Matrix(canvas.getMatrix());
matrix.postTranslate(10, 10);
canvas.concat(matrix);
Canvas.drawBitmap(Bitmap, matrix, Paint);
Matrix matrix = new Matrix();
matrix.postTranslate(10, 10);
canvas.setMatrix(matrix);
Canvas.drawBitmap(Bitmap, matrix, Paint);
此時畫出來的結果就還是會在(10, 10)。原本猜想是忘記apply原本canvas的matrix所致,所以改成
Matrix matrix = new Matrix(canvas.getMatrix());
matrix.postTranslate(10, 10);
canvas.setMatrix(matrix);
Canvas.drawBitmap(Bitmap, matrix, Paint);
結果還是(10,10)!結果不小心喵到有Method叫Canvas.concat()。後來改成:
Matrix matrix = new Matrix(canvas.getMatrix());
matrix.postTranslate(10, 10);
canvas.concat(matrix);
Canvas.drawBitmap(Bitmap, matrix, Paint);
最後就成功的畫在(110,110)的位置。百思不得其解的是:
Matrix matrix = new Matrix(canvas.getMatrix()) 應該會等於 canvas.concat(matrix)
因為都會Apply原本Canvas裡面的Matrix參數,於是乎就去看了一下底層的source code

matrix == null ? 0 : matrix.native_instance);
}
看來還要追到NDK那層,不過看起來兩種設定Matrix的方式有些出入,就等未來有空再往底層看了。
2014年9月27日 星期六
StreamTokenizer
最近在實作藍牙時,碰到處理接收資料的問題,原本是用InputStream.read(byte[]),但會碰到字串切割的問題,假設原本想傳送110給App,就有可能會收到1跟10的兩個數字;
因無法判斷何時需要斷點,直覺想到可以自定義分割符號(例如:冒號,100:110:120),如果要自己實作buffer的話又嫌太麻煩。
最後找到Java有StringTokenizer以及StreamTokenizer就可以自動幫我分割好字串(生活變得更加美麗),有興趣的話可以參考範例
參考鏈結:
StringTokenizer http://developer.android.com/reference/java/util/StringTokenizer.html
StreamTokenizer http://developer.android.com/reference/java/io/StreamTokenizer.html
因無法判斷何時需要斷點,直覺想到可以自定義分割符號(例如:冒號,100:110:120),如果要自己實作buffer的話又嫌太麻煩。
最後找到Java有StringTokenizer以及StreamTokenizer就可以自動幫我分割好字串(生活變得更加美麗),有興趣的話可以參考範例
參考鏈結:
StringTokenizer http://developer.android.com/reference/java/util/StringTokenizer.html
StreamTokenizer http://developer.android.com/reference/java/io/StreamTokenizer.html
2014年7月16日 星期三
How to handle binary file by Parse's Cloud Code
最近在開發Side Project的時候,因為不預期有Server Team的support,所以就來玩玩Parse的Cloud Code,這個東西大概在一兩年前就有碰過一次,那個時候是上傳一些感測器的資料,如果超過某個Threshold就要寄送notification到device。
這次的則是用在交易管理,最棒的是Stripe已經是Cloud Code的其中一個module,所以整合的過程不算太複雜;比較麻煩的事,我們需要上傳一包binary到Parse的Storage,如果由Client直接Create Data Object的話,就可以用ParseFile的物件直接搞定,該死的事繞過Cloud Code,它的Input預期是個JSON,這時候就有幾種解法:
1. 把Binary用Base64 Encode後放進JSON,但超過30MB的JSON會不會有其他悲劇發生?!
2. 直接Client端用ParseFile存檔,JSON裡面放上傳成功的URL。因為Binary沒有跟任何一筆Data Object關連,所以從後台Clean Cache的時候(可能)就會清掉。
3. 同上的Idea,但把資料放到S3。一樣很難清掉沒有意義的資料,因為存檔的動作都是由Client進行。
4. 用Pointer!Create 另外一個Table(Class),Client先Create好一筆Data後,把Object Id傳給Server做關聯。
最後我們採用第四種做法,兼具consistance以及簡化的流程。但看了Parse的Free Plan,20GB的儲存空間,以我們的使用情境,大概1000筆訂單後就要開始付錢了:<
2014年7月7日 星期一
Retrofit : A type-safe REST client for Android and Java
Square 雖然是做支付的公司,但也open了許多好用的library,像是OkHttp、Picasso跟Otto等等;目前公司產品內有使用的是Otto,它解決了Activity跟Fragment,或者Fragment跟Fragment之間的雙向溝通(關於Otto改天再寫別篇文章來描述使用情境),而今天要介紹的Retrofit能簡化Client跟Server間的Code。
舉例說明,如果你要對Restful Server拿資料,首先你要開HttpClient,然後把Api的參數(POST/GET/PUT/DELETE以及Parameters)塞進去;因為Android不允許Http Connection跑在UI Thread,所以你必須在包一個AsyncTask;接著要Parsing Response Body,如果是JSON可以用內建的JOSN Library去一層一層get出來,聰明一點就會用Gson Library。對了你別忘記了Http還有很多複雜的情境,像是Response Code : 301/302的Redirect、Cache的功能、Retry的機制等等等等。
完整的程式片段可能會像這樣(別忘了,它還沒辦法handle 301/302、Cache跟Retry的機制):
Retrofit能讓這一切簡單一些,讓您不再畏懼/厭煩對接所有Restful API,關於使用細節就直接參考官方文件。把同樣的程式用Retrofit再寫一次的結果如下:
如果有任何問題,歡迎各位一起討論。
訂閱:
文章 (Atom)