2014年12月18日 星期四

Android 開發(七十八) GoogleCalendar ListView


不知道大家是否有看過這個特效,在滑動的時候listview裡面的圖片會跟著畫面移動
如下圖


第一次看到的時候真的覺得這個特效很特別,很想知道怎麼做的,
所以就花了幾天研究了這個功能.

在經過了初步的研究之後,發現這個功能應該很容易可以達到,

首先需要抓到該 item在畫面的位置,接著只需要針對位置做相對應的滑動即可,

所以列了兩個任務

  1. 可滑動的ImageView
  2. 抓到item在畫面中的位置

關於可滑動的ImageView
一開始的想法是 SlideImage_FirstVersion 
利用改變drawBitmap top的 position來改變圖片顯示的高度,
這個方法實際用起來的感覺有點頓頓的,所以後來這個寫法就被改寫了

第二個想法是 SlideImage_SecondVersion
利用改變scrollY 去改變可視的範圍
這個方法看起來是可行的,也不會造成額外的performance issue

當完成了上面的功能時,我以為可以很快的完成這個功能,
殊不知困難的會是在第二點,如何抓到item在畫面中的位置是非常困難的,

一開始是使用 recyclerView.getChildAt(index).getTop()
在看了debug log之後就知道這個方法是行不通的,這個方法取得的getTop並不是某個index的view的高度. 所以必須另尋他法,

接著使用了getLocationInWindow(location); 
這個方法也行不通,取得的高度也不是所預想的高度
在所有的方法都不可行的情況下,只好先暫緩這個功能的開發.

就在暫停開發的隔天,在逛Github的時候碰巧看到了ItemDecoration的 implements
覺得很有趣所以就稍微點進去看了一下,
不看還好,看了一下就發現這不就是我尋找已久的解法嗎,
就可以取得view的位置.

有了這兩項工具,就可以完成該功能了

最後,附上該 openSource

https://github.com/nightbear1009/GoogleCalendarListView

2014年12月15日 星期一

AngularJS - two way binding

小弟跟Html 以及javascript其實是完全不熟,由於最近公司有提供AngularJS的教程,
小弟從以前就對網頁就有極大的興趣但是一直找不到機會切入這個領域,所以這次就順便去學了AngularJS,在這邊就稍微記錄一些筆記囉!!


今天要講的是Binding的功能,由於以前就寫過windows app 所以對於binding這個功能並不陌生,binding有分為 one-way binding ,two-way binding, one-time binding
one-way binding 和 two-way binding最大的差別就是在於,資料被設定之後是否會被更新到view ,

例如  sample 的輸入框被鍵入文字時,顯示框會同時顯示鍵入的文字,
這個就是two-way binding 的功能

至於 one-time binding 在於,該資料只會被設定一次,之後就不會再被更動.

2014年12月2日 星期二

Android 開發(七十七) Activity Animations

先看一下下面的功能


我相信大部分的人都知道在5.0的時候有新增一個新的activity transaction的功能
讓我們可以在Activity 替換之間有一些動畫,but......what about 5.0以下呢?

今天就是要來說我們如何可以在5.0以下完成這個功能
首先我們可以將這個動作分成兩個部分
1.enter animation
2.exit animation

Enter animation

首先我們先看enter animation ,讓我們將速度放慢再看一次


我相信仔細看之後可以發現,enter animation(粉紅色塊)
其實是從button大小漸漸地放大到整個畫面,

所以我們要做的事情其實很簡單


  • 先將下一個view縮小到跟button一樣大的size
  • 將view恢復到跟原本的view一樣大的size


but 我們是要startActivity耶,這並不是單純的把view 縮小並且恢復正常而已
所以必須要有額外的步驟

1.首先我們必須取消activity原本的transaction功能

            // Override transitions: we don't want the normal window animation in addition
            // to our custom one
            overridePendingTransition(0, 0);


所以我們必須 開啟粉紅色activity之後呼叫上面的程式碼,避免startactivity之後的default animation

2.接著我們必須將下一個activity用成透明的

    <style name="Transparent"  parent="android:Theme.Holo.Light.DarkActionBar">>

        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>


3.接著就到了將view縮小到跟button一樣大然後再慢慢恢復的動作了
為了達到這個目的我們必須先取得button的位置以及size

        int[] screenLocation = new int[2];
        view.getLocationOnScreen(screenLocation);
        intent.putExtra("left", screenLocation[0]).
                putExtra("top", screenLocation[1]).
                putExtra("width", view.getWidth()).
                putExtra("height", view.getHeight());


然後再將粉紅色activity的view 轉換到跟button一樣大的size和一樣的起始位置,

        mView.setPivotX(0);
        mView.setPivotY(0);
        mView.setScaleX(mWidthScale);
        mView.setScaleY(mHeightScale);
        mView.setTranslationX(mLeftDelta);
        mView.setTranslationY(mTopDelta);

setPivotX/setPivotY  設定animation的動畫起始點,
setScaleX/setScaleY 將粉紅色的view縮小到跟button一樣大
setTranslationX/setTranslationY 將粉紅色的view移動到跟button一樣的位置
在初始設定完成之後,接著就是要將他恢復到原本的大小

      mView.animate().setDuration(duration).
                scaleX(1).scaleY(1).
                translationX(0).translationY(0).
                setInterpolator(sDecelerator);


這部分就相對簡單許多.
這樣enter animation的部分就完成了
接下來就要談exitAniamtion

Exit animation


exit animation相對於enter animation單純許多,
我們要做的動作就是

1.將粉紅色的view縮小到button的size以及位置並且漸漸的變透明
2.finish activity

所以程式碼如下


        mView.animate().setDuration(duration).
                scaleX(mWidthScale).scaleY(mHeightScale).
                translationX(mLeftDelta).translationY(mTopDelta);

        ObjectAnimator bgAnim = ObjectAnimator.ofFloat(mView, "alpha", 0);
        bgAnim.setDuration(duration);
        bgAnim.start();


這個動作就是將粉紅色的view縮小並位移到button的位置,
接著將activity finish掉即可


最後附上sourceCode

reference可以去參考Chet Haase 的
https://www.youtube.com/watch?v=CPxkoe2MraA
基本上這篇文章是聽完他的youtube再花點時間研究程式碼之後的成果

2014年11月26日 星期三

Android 開發(七十六) split icon effect

不知道大家有沒有看過這個影片




裡面的這個這個劈腿真的很厲害,
所以我也希望我們的android icon也可以做到類似的問題
恩....扯得有點遠了XD

其實我只是想做到將一張圖片分開的特效XD 如下圖


這個特效其實概念很簡單,首先將我們的image 切成四個等分,
之後利用移動的距離來分別移動我們四個bitmap即可

首先,我們遇到的第一個問題是該如何將一張完整個圖片分成四個等分?


    private Bitmap createRightUp() {
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas myCanvas = new Canvas(bitmap);
        myCanvas.clipRect(new Rect(getWidth() / 2, 0, getWidth(), getHeight() / 2));
        super.onDraw(myCanvas);
        return bitmap;
    }

首先我們必須先創建一個跟圖一樣大小的bitmap,接著利用clipRect將圖裁減成希望的大小或者圖型,向我這邊就是裁減出右上角的圖,當我call super.onDraw時就會將圖片畫在我的bitmap上,接著我們只需要將我的bitmap畫在view的canvas上即可
canvas.drawBitmap(rightup, deltaY, -deltaY, null);

第一個問題這樣就解決了,那麼接下來是第二個問題
我該怎麼讓四張bitmap移動?

首先我們可以利用touchevent來計算出移動的距離,
然後我們只需要將bitmap畫在canvas上的位置做相對的移動即可也就是
canvas.drawBitmap(rightup, deltaY, -deltaY, null);
裏的deltaY

這樣就可以完成我們想要的功能了

講了那麼多,最後還是附上sample


2014年10月30日 星期四

Android 開發(七十四) extract string to xml

相信每個開發app的開發人員都會有這個經驗,每次要將字串抽到string.xml裡的時候
都要花很多時間,不知道android studio有沒有提供什麼快速的方法呢?

答案當然是有的



首先先選取字串 -> 按下 alt + enter  -> extract string resource -> keyin your resource name -> done

話說...最近越來越懶人模式了XD



2014年10月28日 星期二

Android 開發(七十三) jsonToJava

我相信目前大部分的人都是使用Gson來接資料,
但是在接資料的時候會發現,每次新的api都要自己建model很麻煩....
尤其是當model很多層的時候就會花很多時間在這個上面

好啦...其實是我很懶...

所以,我就稍微搜尋了一下相關的tool 然後就找到了
http://jsontojava.appspot.com/


這個要怎麼用? 首先將你的dummy api或者是實際上要串接的api的網址丟入
並且填入你要的package name 和 folder name 還有是否要使用parceable/gson

接著等個幾秒鐘,你的model就完成了
最重要的是,他有提供command line,所以只需要寫個簡單的script就可以在local
快樂的使用這個功能了!!

2014年10月23日 星期四

Android 開發(七十二) Regex開發

我想有一點開發經驗的developer都會遇過同樣的情形,
在android上寫regex是非常痛苦的一件事,

因為語法不熟,所以常常要測試語法是否有寫錯,可是
總不能每寫一次語法就build一次,這樣實在太花時間,為了解決這個問題
我稍微搜尋了一下android studio的plugin

Regex Tester個人覺得是蠻方便的工具



















只需要在上方打入reg語法,下方寫入你要match的文字,他就會自動幫你check了
不再需要build就可以直接測試,速度快多了

設定環境變數

當要設定環境變數時,可以利用以下的方式做設定,

vi ~/.bash_profile

然後在文件裡key入路徑即可

export ANDROID_SDK_HOME=~/Documents/adt-bundle-mac-x86_64-20140321/sdk

export PATH="$ANDROID_SDK_HOME/tools:$ANDROID_SDK_HOME/platform-tools:$ANDROID_SDK_HOME/build-tools/17.0.0:$PATH"

2014年10月22日 星期三

Android 開發(七十一) Gradle 查詢可執行command

常常會遇到要下gradle command的時候卻不知道該怎麼去下command

例如我今天想要看 dependencies tree ,可是卻不知道該如何下commnad

gradle 有內建一個非常方便的功能

gradle -q task --all

這個commnad會將所有可執行的task 列出來,有點像是ls的感覺...

你可以利用這個command找到你希望執行的command


以下是我下 gradle -q task --all的部分可執行 command

Android tasks
-------------
actionbarsherlock:androidDependencies - Displays the Android dependencies of the project
app:androidDependencies - Displays the Android dependencies of the project
DataDroid:androidDependencies - Displays the Android dependencies of the project
FacebookSDK:androidDependencies - Displays the Android dependencies of the project
slideMenu:androidDependencies - Displays the Android dependencies of the project
viewpager:androidDependencies - Displays the Android dependencies of the project


從上面可以很清楚的知道,假設我要看我project的 dependencies
我只需要執行  gradle  app:androidDependencies 




2014年10月16日 星期四

Android 開發 (六十九)DrawerArrowDrawable

我想用過 material design L 的人都看過以下的ui



但是有人想過這個功能要怎麼完成嗎?

前幾天看到ChrisRenke po出了一篇完整分析的文章,他的做法令人非常的驚豔(至少我是如此XD)

接下來我們就來介紹他是如何完成的

首先他針對menu上的三條線做了分析,
from chrisrenke

以上這張,有三個顏色,紅,藍,菊,分別代表著上,中,下,三條線,
所以這張圖可以完整地看出三條線的移動路徑,不過非常的雜亂,所以作者經過整理之後
變成了下面這張圖

from chrisrenke

這張圖其實就是在說明,線實際運作的軌跡,我們可以用下面這張圖來進一步說明,
from chrisrenke

上面較長的黑色橫線就是一開始最上面的那條線,然後結束之後會抵達,斜約45度角的線,
實際上的樣子會是如下圖



一開始是走藍色的路徑,當數值大於0.5的時候就會走黑色的路徑
我想這樣大家應該比較看得懂,他的路徑是怎麼走的了,
既然我們已經了解了他實做的方式,接下來我們就需要在我們的android中實做出來,

首先,我們必須實做上面的兩個圓弧,
so....我們可以利用 path 來完成這個功能,

也就是如下的程式


first = new Path();
first.moveTo(5.042f, 20f);
first.rCubicTo(8.125f, -16.317f, 39.753f, -27.851f, 55.49f, -2.765f);
second = new Path();
second.moveTo(60.531f, 17.235f);
second.rCubicTo(11.301f, 18.015f, -3.699f, 46.083f, -23.725f, 43.456f);
scalePath(first, density);
scalePath(second, density);
joinedA = new JoinedPath(first, second);
first = new Path();
first.moveTo(64.959f, 20f);
first.rCubicTo(4.457f, 16.75f, 1.512f, 37.982f, -22.557f, 42.699f);
second = new Path();
second.moveTo(42.402f, 62.699f);
second.cubicTo(18.333f, 67.418f, 8.807f, 45.646f, 8.807f, 32.823f);
scalePath(first, density);
scalePath(second, density);
joinedB = new JoinedPath(first, second);
topLine = new BridgingLine(joinedA, joinedB);

上面的四個path就代表著藍色黑色弧形,JoinedPath其實只是要方便參照,當值<0.5時參照
JoinedPath的first Path當>0.5時參照second Path,
而其中最關鍵的技巧就是,measureFirst.getPosTan(lengthFirst * parameter, coords, null);
利用這個當 <0.5時,就會去參考 JoinedA的 first Path  與  JoinedB的 first Path的第一個點,

也就是上圖的兩個藍色圓弧的第一個點,也就是橫線時的起始點,
當完成了第一條線,剩下的兩條線也是相同的邏輯,在這裡就不再多提

只能說想出這個解法的人真的很厲害,相信他花了很多時間才完成這個功能,不過同時
我們也從他的這個方法中學到如何利用path以及param的改變,來改變view.

真的是獲益良多!!~  最後歡迎有興趣的各位可以去參考他的source code

http://chrisrenke.com/drawerarrowdrawable/
https://github.com/ChrisRenke/DrawerArrowDrawable

2014年10月2日 星期四

[RefactoringToPatterns] Replace Constructors with Creation Methods

最近開始看 RefactoringToPatterns 最近應該會開始分享這本書的一些心得,
 今天就先來分享 Replace Constructors with Creation Methods吧
 作者在一開始就列出了兩個範例



哪個看起來比較能清楚表達我們要創建什麼物件?

我相信大家都會選擇下方的選項,
Replace Constructors with Creation Methods的意思就是

        以目的清楚, 返回物件實體的Creation Method 取代建構式

然而使用這個方法雖然能夠讓我們清楚了解要創建什麼物件,相對的他也帶來了部分的缺點

優點:
  • 比建構式更能表達要創建哪種物件
  • 突破建構式的限制,不能同時擁有兩個  引數個數和引數型別君相同的建構式
  • 更容易找出未使用的創建式
缺點:

  • 創建的方式變得不標準,以上面loan的例子來說:我們可以用new Loan(...)
    也可以用  Loan.createTermLoad(...)


至於該如何實做,這邊附上一個很小的範例


public class Loan {

    public Loan(int a, int b) {

    }

}

原本的建構式是長這個樣子,經過refactoring 之後


public class Loan {
    
    private Loan(int a,int b){
        
    }
    
    public static Loan createTermLoan(int a,int b){
        return new Loan(a,b);
    }
}

可以很清楚地看到,我們使用了static method來創建我們的Loan
這樣之後要創建Loan時我們只需要call Loan.createTermLoan即可

最後,作者也有提到,當我們的物件裡含有太多的creation method,
而這些method開始混淆這個class原本該做的事情時,根據單一責任原則,
我們可以將Creation method 再度重構為Factory.
如下圖所示


2014年9月25日 星期四

Prezi



之所以會介紹Prezi,是因為看到他特別的presentation方式,每次在報告的時候都覺得powerpoint非常的單調,覺得少了什麼.... 前陣子去參加聚會的時候,意外看到了Prezi,深深的被他特別的present方式給吸引,我想最近應該會轉用這種東西做投影片了吧!! 上面是我稍微玩一下的作品,可以看出他特別的呈現方式. 在這邊介紹給大家

2014年9月23日 星期二

Android 開發(六十八) listview header animation

最近由於工作的需要寫了一個很簡單的listview header的 animation


這個animation看起來很簡單,實際上也真的是不難啦...不過真的花了我不少時間tune...

首先,我們要做的事情很簡單,就是在itemclick的時候,把header長出來,然後當header長出來之後,在重新click一次就會退回去,所以我們首先會先想到使用
translationY的這個 property.

ObjectAnimator animX = ObjectAnimator.ofFloat(listview, "translationY", 0f, -textview.getHeight());
ObjectAnimator animY = ObjectAnimator.ofFloat(textview, "translationY", 0f, -textview.getHeight());


利用上面的code我們就可以依照我們希望的方法將head (Textview)長出來/藏起來了

But.........
事情永遠不會是我們想的那麼簡單,當利用tranlationY將view往上移動之後就會發現,整個listview變短了,為了避免掉這個問題,所以我們必須在移動完成之後,將listview的height 往下延伸,那要怎麼做?

RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) listview.getLayoutParams();
p.bottomMargin = -textview.getHeight();
listview.setLayoutParams(p);
這樣就可以做出一個簡單的動畫了,最後附上原始版 gist 供大家參考,
ps. code寫的非常凌亂而且有很多地方還可以修改,只是為了展現功能而寫的.


2014年9月15日 星期一

Android 開發(六十七) Triangle drawable

最近有個需求,需要我們利用程式來畫三角形,當下小弟是一點頭緒都沒有,
還好平時有在讀別人code的習慣,就想到了可以使用Path來畫我們需要的圖形,

首先我們必須先選出三角形的三個頂點,


 Point a = new Point(paddingLeft+0+stroke, Math.max(canvas.getHeight()/3*2-(int)TriHeight-stroke,0));
     Point b = new Point(paddingLeft+(int)TriBottom*2 +stroke, Math.max(canvas.getHeight()/3*2-(int)TriHeight-stroke,0));
     Point c = new Point(paddingLeft+(int)TriBottom+stroke, Math.max(canvas.getHeight()/3*2-stroke,0));


上面的三個頂點,會畫出一個倒三角形






會置放在canvas的3分之2的位置,在決定了三個頂點之後,接著就只需要利用PATH將圖畫出來即可,


     Path path = new Path();
     path.setFillType(FillType.EVEN_ODD);
     path.moveTo(a.x, a.y);
     path.lineTo(b.x, b.y);
     path.lineTo(c.x, c.y);
     path.lineTo(a.x, a.y);
     path.close();


上面的程式讓我們可以填滿三角形,並描繪出該三角型。 詳細的程式碼可以參考 https://gist.github.com/nightbear1009/ad4d9d96faeb7a756931

2014年9月10日 星期三

Android 開發(六十六) gradle rebuild 但是修改的參數並沒有被更改

利用 gradle build --rerun-tasks 例如: 在build.gradle 裡寫入這樣的參數 ext { ga_apptracker = "UA-123456-1" ga_global_logLevel = "verbose" ga_global_dryRun = "true" } 然後利用gradle replace掉特定的參數 這個情形在第一次的時候會順利更改資料,但是不知道為何之後就不會再被更改, 即使rebuild也沒有用,我猜測是因為 android studio 將該檔案視為 update to date 所以並不會重新被更動 這樣可以確保project重新 rebuild ,雖然這樣會很花費時間, 但是可以確保build.gradle檔案裡的資料會被更新成最新版本的資料 不過...如果只是要確保每次都會執行,目前有較好的做法 task GABuildValueCopy <<{ copy { ...dosomething } } 在android studio 0.8.6 這樣寫就可以確保每次執行該task都會被執行到

2014年8月21日 星期四

Android 開發(六十五) Gradle 出現 unable to locate a java runtime to invoke

在command line key這些指令之後
$ chmod +x ./gradlew
$ ./gradlew assembleDebug
再重新build即可

目前還不知道為何會發生這個事情...

Android 開發 (六十四) Gradle replace and copy file

在prebuild時要如何修改 xml 裡的檔案?
例如  我們有個buildvalue變數  希望在build的時候做修正




首先必須先創建一個template 接著template中的字串做match 並replace之後將檔案複製到原本的build folder中










照著上面的方法寫,我們必須手動的在build之前打入指令
gradle myCopy
然後等到他完成之後才可以執行 grdle build
也就是說task並不會自動被執行

所以我們可以在gradle file中加入






這代表著在prebuild之前必須先執行 myCopy結果如下
















:app:myCopy代表有跑到myCopy這個task
這樣就會完整執行到我想做的事情了

Android 開發 (六十三) Gradle Flavor

Flavor  利用flavor 可以修改 packageName versionCode versionName
在build.gradle 下新增 productFlavors 設定希望的值
並且在Manifest中做相關設定即可
例如   applicationId 在這邊為 packagename   然後在 manifest中 將參數寫成 ${applicationId}  在build的時候就會置換































利用上面的方式,我們能夠輕鬆的替換package name
接著該如何利用不同的flavor替換不同的ui呢?


假設我們有100間店,以及1000種ui
那我們就需要兩個參數來控制色碼和店家
首先我們先在 flavorDimensions  中定義 color and shopNum 




接著定義各個color 以及 shopNum要吃的參數
如下  color1的 flavorDimension 為color代表著  color1 是代表color參數而
shop1 的 flavorDimension為 shopNum代表著 shop1代表著shopNum的參數
可以看到我們在color1 以及shop1 中各定義了一些參數














由於我們必須換圖 為了達到這個目的,我們只需要在folder中創建 color1 and color2 














接著當我們要build的時候  只需點選左下角的 build Variants  接著選取我們要build的項目即可,
color1Shop1Debug  or  color2Shop2Debug ...etc

2014年8月14日 星期四

Android 開發 (六十二) Drawable mutate

先看一下這段code

public static class MyAdapter extends BaseAdapter {
   private LayoutInflater inflater;

   public MyAdapter(Context context) {
    inflater = LayoutInflater.from(context);
   }

   @Override
   public int getCount() {
    // TODO Auto-generated method stub
    return 10;
   }

   @Override
   public Object getItem(int arg0) {
    // TODO Auto-generated method stub
    return arg0;
   }

   @Override
   public long getItemId(int arg0) {
    // TODO Auto-generated method stub
    return 0;
   }

   @Override
   public View getView(int arg0, View arg1, ViewGroup arg2) {
    View view = inflater.inflate(R.layout.listview_layout, null);
    CheckBox check = (CheckBox) view.findViewById(R.id.check);
    Drawable d= inflater.getContext().getResources()
      .getDrawable(R.drawable.icon_item_small_selected);
    if (arg0 == 1) {
     d.setAlpha(255);
    } else {
     d.setAlpha(70); 
    }
    check.setButtonDrawable(d);

    return view;
   }

  }

看起來非常的正常,只不過是在position為1的時候將透明度改成255其他時候為70
但是結果是如下面這張圖...  我們會發現position 1的透明度竟然不是255.....







這其實是因為當getdrawable取得同一張圖時其實是共用resource而且共用state ,
所以當你針對某一張圖做更改時,其實同時也改到了其他共用的view


那要怎麼解決?    mutate 

接著讓我們將原本的code 加入 mutate


   @Override
   public View getView(int arg0, View arg1, ViewGroup arg2) {
    View view = inflater.inflate(R.layout.listview_layout, null);
    CheckBox check = (CheckBox) view.findViewById(R.id.check);
    Drawable d = inflater.getContext().getResources()
      .getDrawable(R.drawable.icon_item_small_selected);
    if (arg0 == 1) {
     d.mutate().setAlpha(255);
    } else {
     d.mutate().setAlpha(70); 
    }
    check.setButtonDrawable(d);

    return view;
   }

讓我們再看一次結果


everything works.

2014年8月13日 星期三

Android 開發 (六十一) Splash Screen

不知道各位是否有遇過,打開APP時總是一片空白,或者是start一個新的activity時,畫面總是空白,如下圖所示,在app開起的瞬間是一片白色畫面,過了幾秒鐘之後,所有的ui才一起出現,這其實並不是BUG,而是android先去load了 activity的 Theme之後才去讀取你的App畫面。



既然知道問題的原因,那要解決這個問題的辦法也很簡單,我們只需要將開啟app時所load的Theme換掉就好了。

可以看到從一打開app我們想顯示的logo就一直存在,再也沒有白畫面的問題,
這樣就可以製作出Splash Screen了。

好了,原理講完了,接著就是該如何實作,
首先要先製作Splash Screen的頁面



<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item>
        <shape android:shape="rectangle" >
            <solid android:color="#FFFFFF" />
        </shape>
    </item>
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/ic_launcher" />
    </item>

</layer-list>

接著客制化我們的Style
    <style name="myTheme" parent="Theme.AppCompat.Light">
        <item name="android:windowBackground">@drawable/mylayer</item>
    </style>

接著將我們的style套到我們的Activity上

        <activity
            android:name="com.yesnews.sample.MainActivity"
            android:label="@string/app_name"  
            android:theme="@style/myTheme"
            >

           ......


如此就大功告成了!!
我們想要的Splash Screen不再會有白畫面的問題了~

2014年7月23日 星期三

Android 開發 (六十) 開發第一支自己的app

小弟最近下班花了點時間,開發了一支Rss Reader,
甚麼是Rss Reader呢?  其實就是去截取各個網站的Rss 文章,並且截取到我的app中

(一)要如何取得Rss的資料呢?

其實有很多resource, 像是google api 、 feedly、newsBlur ,
不過小弟覺得feedly比較符合需求,所以就使用了feedly當作主要的資料來源,
feedly的api其實很容易使用,下面的網站有相關的資料,http://developer.feedly.com/


(二) 快速的開發

由於小弟開發的時間只有下班時間,而且並不是每天都能夠順利的進行開發,在時間很零碎而且不足夠的情況下,要如何提升開發效率就是另一個問題了,為了要達到快速開發的目標,就必須減少建構基礎架構的時間,所以小弟使用了許多github上的resource來加速開發,

https://github.com/astuetz/PagerSlidingTabStrip
https://github.com/etsy/AndroidStaggeredGrid
Gson
jsoup
https://github.com/nostra13/Android-Universal-Image-Loader
https://github.com/square/retrofit
https://github.com/greenrobot/EventBus
https://github.com/bauerca/drag-sort-listview
https://github.com/dmytrodanylyk/circular-progress-button

首先利用PagerSlidingTabStrip、circular-progress-button 來完成較好的UserExperience ,



AndroidStaggeredGrid 來完成較特殊的layout排法,


Gson 、jsoup、 ImageLoader 幫助我資料的轉換以及取得網頁的資料還有圖片的讀取
retrofit負責 http get and post
EventBus負責元件間的資料傳遞
drag-sort-listview讓我能夠快速的完成重新排序以及刪除訂閱資料的功能


講了那麼多,最後當然要附上下載連結給大家參考一下 XD

https://play.google.com/store/apps/details?id=com.yesnews.sample


說了那麼多,挑戰其實是在app release之後啊XD

Android 開發 (五十九) Eclipse with ProGuard

在 crashlytics 介紹中有提到如何使用crashlytics,但是在經過proguard之後,所有的crash

log都被混淆無法判斷錯誤的來源,要如何解決這個問題呢?

crashlytics的網站中有提到相關的解法


如下

Eclipse with ProGuard

Crashlytics automatically de-obfuscates stack traces in your crash reports. You’ll never manually retrace a stack trace or hunt around for a lost mapping file again!
For Crashlytics to provide the most informative stack traces, add the following line to your ProGuard configuration file:
-keepattributes SourceFile,LineNumberTable
When building for release with Eclipse, export your application to an APK using the “Export Crashlytics-enabled Android Application” exporter from the Eclipse export menu. Just go to File -> Export -> Android :)
This exports your application using the standard ADT Android Application exporter and then uploads the ProGuard-generated mappings file to our servers.
If you make release builds using the command line, please see the appropriate article for your build system:

2014年7月20日 星期日

Android 開發 (五十八) easy way to get facebook Response data

使用facebook的api 例如 使用facebook SDK po 塗鴉牆 以及tag好友
裡面所使用的post wall 裡的call back

public void onCompleted(Response response) {
      // do something
}

通常我們取得資料後會將回傳資料轉成string然後再依照 gson的方式去取得資料,
不過當我們使用facebook的response時,我們會發現他有
public final GraphObject getGraphObjectAs(Class graphObjectClass)的method,然而在facebook的文件裡面沒有提到的是,我們可以利用這個api來取得想要的資料,舉例來說,假設我們知道回傳的資料裡有id,那我們可以定義一個interface如下

interface MyDataGetter{
   int getId();
}


MyDataGetterresult = response.getGraphObjectAs(MyDataGetter.class);

我們可以輕鬆的取得我們需要的資料。

2014年7月9日 星期三

Android 開發 (五十六) Gradle 如何增加lib

Gradle 跟eclipse的行為很不一樣,在eclipse中當我們缺少lib,需要將lib檔加入 libs folder或者加入 android lib中


但是在 android studio中一切都變了,如今...要import library變得更簡單,我們不再需要繁瑣的import 沒用的project,也不需要每次為了幫別人架設環境用半天了

在 Android Studio 中我們可以利用 file -> Project Structure -> Dependencies 增加我們需要的lib


假設我們需要import external的lib,變得更簡單了,以前我們可能必須import一大堆的project到我們的專案中,現在這一切已經不再必要,你只需要知道版本號之後只需要在上面的search欄中填入你的lib 並且點選ok就完成了,舉個簡單的例子,例如我的project想要import eventbus這個功能
我只需要將 
dependencies {
    compile 'de.greenrobot:eventbus:2.2.1'
}
加入我的dependencies中即可,剩下的gradle會幫你解決所有的問題。

真的是超級方便啊,不過最近在0.81 版本上遇到一個問題,

Manifest merger failed : uses-sdk:minSdkVersion xx cannot be smaller than version L declared in library com.android.support:support-v4:21.0.0-rc1

感覺是0.8的bug,看起來是因為gradle設定檔內使用
compile 'com.android.support:support-v4:+' 造成 gradle去使用最新版本的 support-v4 然而最新版本的 support-v4似乎只支援 L, 所以必須將上面的 dependencies 改成  compile 'com.android.support:support-v4:20.0.0' 這樣就解決了。

Android studio真的很方便,而且也進入beta了,如果是寫新app的人可以直接切過來了,至於必須維護舊app的人,這條路也是必經之路,現在這個時間點也是可以考慮切換的時候了,畢竟eclipse真的很麻煩啊XD。

Android 開發 (五十五) GoogleCloudMessaging

最近在玩Gradle的時候意外發現

GCMRegistrar  Is  Deprecated  



我記得在我剛接觸android時...GCM才剛改版過...如今過了不到一年...他又改版了...

雖然說又改版了,不過使用方式並沒有太大的改變。只是新版的register不能在MAIN_THREAD中執行,必須使用async task去做...

附上簡單的執行片段


        new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... params) {
                String msg;
                try{
                    GoogleCloudMessaging gcm;

                    gcm = GoogleCloudMessaging.getInstance(getApplicationContext());

                    String regid = gcm.register(SENDER_ID);
                    Log.d("Ted","id "+regid);
                    msg = "Device registered, registration ID=" + regid;
                } catch (IOException ex) {
                    msg = "Error :" + ex.getMessage();
                    // If there is an error, don't just keep trying to register.
                    // Require the user to click a button again, or perform
                    // exponential back-off.
                }
                return msg;
            }

            @Override
            protected void onPostExecute(String msg) {

            }
        }.execute(null, null, null);

regid 就是server訊息傳送時所需的token,根據sample code的寫法,只有在第一次執行的時候才會執行register 其他時候都是由sharepreference取得之前的regid (這代表著regid不變?這點我很懷疑)。

其他的使用方式跟以前沒太大的差別,有興趣可以參考 Hello GCM
最後附上 sample code