Android Dialog

dialog可以說是超常用也超好用,其實官網就有很完整的範例,但是在custom dialog部份有點讓人看不懂(至少我是...)



xml的部份我想就不必多說,跟官網一樣也可以,new出來的部份就有點不同
Dialog dialog = new Dialog(AAAAA.this);
dialog.setContentView(R.layout.dialog_login);
dialog.setTitle("測試一下");


AAAAA的部份就是class的名稱
title就看使用時自己訂,當然也可以從strings.xml取得
內容就直接從xml去繪製,而按鈕、所有東西要使用也是跟一般一樣要先跟R.java做好連結

相關連結
Android Developers
Android Developers Creating Dialogs

Android Resources strings

建立Android專案時就會自動產生strings.xml(位置於專案/res/values/strings.xml),這簡單來說就是把文字部份拉出來整理,需要做多國語言時相當的重要,就算不是要作多國語言建議還是用一下,不然哪天為了找一個字串還要找半天,而且裡面不只可以放單一字串,字串的陣列也可以。

單放字串
<string name="app_name">我是懶人</string>

app_name就是這字串的帶稱想要使用時在一般xml檔就如下列用法
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name">
</TextView>


但總是會遇上需要在.java內要用上的時候,以上方那個TextView為例
text.setText(getString(R.string.app_name));

字串陣列在strings.xml檔內
<string-array name="myArray">
<item>11111</item>
<item>22222</item>
<item>33333</item>
</string-array>


<!-- 也可以直接抓取string內容來用 -->
<string name="red">Red</string>
<string name="orange">Orange</string>
<string name="yellow">Yellow</string>
<string name="green">Green</string>
<string name="blue">Blue</string>
<string name="black">Black</string>

<string-array name="colorArray">
<item>@string/red</item>
<item>@string/orange</item>
<item>@string/yellow</item>
<item>@string/green</item>
<item>@string/blue</item>
<item>@string/indigo</item>
<item>@string/violet</item>
</string-array>


取得陣列
Resources res = getResources();
String[] array = res.getStringArray(R.array.myArray);

//直接寫在一起
String array[] = getResources().getStringArray(R.array.colorArray);


相關連結
Android Developers
Android Developers R.string

Android SharedPreferences

簡單來說就是儲存些變數在app內部,如同iOS可以存在app內的plist一樣,plist可以存array、dictionary、integer、boolean、number、string......等,目前沒多去試android這是否也這麼齊全,但至少可以用key/value的方式來存一般來說也夠了,真的要多存點東西就可以考慮用sqlite

儲存
SharedPreferences myPreferences = getSharedPreferences("myPreferences", MODE_PRIVATE);
SharedPreferences.Editor e = myPreferences.edit();
e.putInt("myInteger", 1000000);
e.commit();


e.putInt這邊可以自己選擇型態,懶一點跟我一樣就補全再上下選擇要用的就好

讀取
SharedPreferences myPreferences = getSharedPreferences("myPreferences", MODE_PRIVATE);
int i = myPreferences.getInt("myInteger", 0);


myPreferences.getInt("myInteger", 0);
getInt("變數名稱", 預設變數);

相關連結
Android Developers
Android Developers SharedPreferences
Android Developers SharedPreferences.Editor

Android Activity 切換傳參數

Activity在參數間互傳應該也算是個相當常用上的功能
兩個Activity就像傳球一樣一個丟另一個接
由於我腦容量比較小還是來紀錄一下...以防忘記

現在狀況是ActivityA切換到ActivityB
然後丟一個參數過去

ActivityA找個要切換的地方寫上
Intent intent = new Intent();
intent.setClass(this, ActivityB.class);
Bundle bundle = new Bundle();
bundle.putInt("KEY_A", 1);
intent.putExtras(bundle);
startActivity(intent);


注意:
1. intent.setClass(this, ActivityB.class);,這中間的this如果不是直接寫在Avtivity下面那層會出現錯誤,只需要更正為
intent.setClass(ActivityA.this, ActivityB.class);

這個this在objectC中就像是self,但是又不大相同,常常會用上,但是要小心

2. bundle.putInt("KEY_A", 1);,bundle中可以依照需求增加更多參數,不限制Integer一種型態,就算是String、boolean、......各種型態都可以,自動補全按下去慢慢挑就好(如下圖)

裡面的("KEY_A", 1)就是常用的key/value,objectC中就是NSDictionary

ActivityB這端來接
Bundle bundle = this.getIntent().getExtras();
int key = bundle.getInt("KEY_A");
//System.out.println("key = "+key);


注意:
1. int key = bundle.getInt("KEY_A");這邊就依照key名稱去對應所得到的value,getInt也需要依照類型的不同更改為getString等的方式去更改型態,等號前面的型態也記得要與等號後方相同

--
前面的部份是單純傳過去,那如果Activity傳過去後在ActivityB執行過程中還需要切回ActivityA,或者兩邊可能要同步作一些動作就需要再加上一點東西

ActivityA原來上面那段稍作修正
Intent intent = new Intent();
intent.setClass(this, ActivityB.class);
Bundle bundle = new Bundle();
bundle.putInt("KEY_A", 1);
intent.putExtras(bundle);
//startActivity(intent); //修改這行
startActivityForResult(intent, 0);


ActivityA再內加上
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//TODO something
//System.out.println("requestCode = "+requestCode+" || resultCode = "+resultCode+" || data = "+data);
int keyB = data.getExtras().getInt("KEY_B");
//System.out.println("keyB = "+keyB);
}


其中data就是你所回傳的intent,從其中取出bundle所帶的值即可

ActivityB需要執行回傳的地方加上這段
Bundle bundle = new Bundle();
bundle.putInt("KEY_B", 1);
setResult(RESULT_OK, (new Intent()).putExtras(bundle));


由於跟上面一樣就不再多加敘述


當然還可以用更多的方式來傳參數,這只是其中的一個解決方案。

相關連結
Android Developers
Android Developers - Activity class

Android EditText Listening soft keyboard

EditText是個基礎元件,基本預設按下去就會彈出鍵盤來讓你輸入內容,算是相當人性化,在部份情況下可能只要需要使用"EditText.getText()"來取出文字判斷就好,但在需要即時(如鍵盤按下瞬間就進行判斷)就需要用上其他方式

Listening soft keyboard 檢查軟體鍵盤(就是畫面彈出那個)
EditText.addTextChangedListener(new TextWatcher(){

@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
System.out.println("afterTextChanged || 按下後");
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
System.out.println("beforeTextChanged || 按下前");
}

@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// TODO Auto-generated method stub
System.out.println("onTextChanged || 按下中");
}
});


但是光這樣還是有些鍵是檢查不到的 EX:ENTER(keyCode = 66)、BACKSPACE(keyCode = 67),必須再搭配下面這方式,下面這方是也可以偵測到外接鍵盤(可能對tablet比較常用)
EditText.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
System.out.println("keyCode = "+keyCode);
//return true = finish || false = track
return false;
}
});


如果只是要得到硬體鍵盤、按鍵,可以使用下面這方式
/* hardware keyboard */
@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
//todo something
System.out.println("keyCode = "+keyCode+" || keyEvent = "+event);

//ex: ENTER
if(keyCode == KeyEvent.KEYCODE_ENTER){
//press ENTER
}

return super.onKeyDown(keyCode, event);
}


那如果都是使用外接鍵盤覺得內建鍵盤很礙眼就是要把他隱藏起來
//先宣告
InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

//隱藏起來 soft keyboard
inputManager.hideSoftInputFromWindow(editText.getWindowToken(), 0);

//叫出鍵盤 soft keyboard
inputManager.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);


相關連結
Android Developers
Android Developers - InputMethodManager
Android Developers - TextWatcher
Android Developers - EditText

iOS 檢查網路狀態

有需要連線至網路的app如果沒了網路就跟死魚一樣(如facebook for iphone)
所以沒網路時一定要告訴使用者你現在沒連網路

Download Code

使用方式
step1.把檔案抓進專案中


step2.加入 SystemConfiguration.framework




step3.在.h檔內import
#import "CheckNetwork.h"


step4.在.m檔中使用
CheckNetwork *checkNetwork = [[CheckNetwork alloc] init];
// YES = connect / NO = death
NSLog(@"connectedToNetwork = %d", [checkNetwork check]);
[checkNetwork release];


其實在官方也有個Sample Code也是同樣的功能
不過...小弟我不才看不太懂(明明就是懶...)

-
相關連結
iOS Developer Library
iOS Developer Library - System Configuration Reference
Download Code

iOS 影音媒體播放

一般在使用內建的mediaplay感覺很麻煩
我是個懶人,看到很多code就會想睡
所以就乾脆獨立出個檔案來作比較方便

主要內容如下
1. 播放時全螢幕,調整為適合畫面比例
2. 當device旋轉時影片也會自動跟著轉
3. 只要把URL(string)丟進去就會開始執行了

Download Code

用法一樣很簡單
step1. 把檔案抓進專案中


step2. import MPMediaplayer framework




step3. 在.h將IskenMediaPlayer import進去
#import "IskenMediaPlayer.h"

step4. 在.m檔內使用
IskenMediaPlayer *player = [[IskenMediaPlayer alloc] init];
[player setMediaURL:@"http://XXXXXXXXXXXXX"];
[self presentModalViewController:player animated:YES];



相關連結
iOS Developer Library
iOS Developer Library - MPMediaLibrary Class Reference

Download Code

iOS - 檢查Email格式 check email format for Objc

前幾天稍微找了一下(真的是一下...只點開兩個連結看...)檢查email格式的東西好像沒有針對objc的
反正剛好要用上就順手寫了一下
稍微看過email標準格式後就開始動工
其實也只算是寫個大概...簡單判別一下而已
沒有作email驗證的email address大概90%都是亂寫的吧(至少我自己就是這樣)

大致上判斷以下這些部份
1. 簡單判斷內容是否有特殊字元
2. 是否有手癢多輸入了幾次 @
3. 是否有手癢多輸入幾個 .
4. 結尾有沒有加.com、net、tw...等

Download code

使用方式
1. 先在.h把檔案import進來
#import "CheckEmailFormat.h"


2. 把物件new出來並且判斷
只要把check:後面加入要判斷的email address即可
會回覆你YES/NO
如果是NO會自動彈出一個警告告訴user錯誤
CheckEmailFormat *checkEmail = [[CheckEmailFormat alloc] init];
//retuen 1 = ok || 0 = error
NSLog(@"This Email address is %d", [checkEmail check:@"abc@11111111111111.com"]);
[checkEmail release];


參考資料
iOS Developer Library
iOS Developer Library - NSString Class Reference

Download code

iOS dial a phone call 在app內撥電話

iOS上面並沒有直接呼叫撥號功能的方式,必須透過UIWebView來進行(iOS 3.1後,iOS 3.1前是使用UIApplication),也就是用URL的方式進行撥號,根據官方文件“Mail Links”、“Phone Links”、“Text Links”、“Map Links”、“YouTube Links”、“iTunes Links”等的東西都可以透過url來呼叫,以下就先介紹撥號。

撥號的URL格式為:"tel:1234567890"
如果需要加上#字號 ex:"tel:1234567890#123",請將"#"換為"p" ex:"tel:1234567890p123"
需要二次撥號加上"," ex:"tel:1234567890,123"

NSURL *phoneNumber = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"tel:123456789"]];
if ( [[UIApplication sharedApplication] canOpenURL: phoneNumber] ){
//get iOS version
NSString *osVersion = [[UIDevice currentDevice] systemVersion];
//NSLog(@"iOS version = %@",osVersion);

if ([osVersion floatValue] >= 3.1) {
NSLog(@"iOS version is after 3.1, version = %@",osVersion);
UIWebView *webview = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
webview.alpha = 0.0;
NSLog(@"phoneNumber = %@",phoneNumber);
[webview loadRequest:[NSURLRequest requestWithURL:phoneNumber]];

// Assume we are in a view controller and have access to self.view
[self.view addSubview:webview];
[webview release];

}
else {
// On 3.0 and below, dial as usual
NSLog(@"iOS version is below 3.1, version = %@",osVersion);
[[UIApplication sharedApplication] openURL: phoneNumber];
}
}else{
//can not get phone call
UIAlertView* alert = [[UIAlertView alloc] initWithTitle: @"系統訊息"
message: @"無法順利撥號"
delegate: nil
cancelButtonTitle: @"確認"
otherButtonTitles: nil];
[alert show];
[alert release];
}


撥號成功
系統會自動產生是否確定撥號的訊息


撥號失敗
我們自己寫的警告無法順利撥號


參考連結
iOS Reference Library
iOS Reference Library - Apple URL Scheme Reference

iOS -shouldautorotatetointerfaceorientation 自動旋轉畫面

使用iPhone、iPad、iPod Touch系列產品常常很自然的會把他轉來轉去(如下圖)

圖片來源:http://www.sopods.com/images/apps/FullScreenIPhone_rotation_bars.jpg

根據官方文件(Launching your Application in Landscape)使用起來確實超級簡單(此方法使用於iOS 2.1以後版本)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}


就這樣短短幾行就可以把畫面固定在橫的
Home鍵在右手邊
那如果要轉其他邊或者瘋狂的隨你轉呢
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
NSLog(@"shouldAutorotateToInterfaceOrientation = %d",interfaceOrientation);

if(interfaceOrientation == UIInterfaceOrientationLandscapeRight){
NSLog(@"RIGHT");
//return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft){
NSLog(@"LEFT");
//return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

if(interfaceOrientation == UIInterfaceOrientationPortrait){
NSLog(@"Portrait");
//return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

if(interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown){
NSLog(@"PortraitUpsideDown");
//return (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
return YES;
}


僅只需要將最後的return設定為YES畫面就會隨著你轉
想要固定在某一邊只需要改成return下面這幾個
上:UIInterfaceOrientationPortraitUpsideDown
下:UIInterfaceOrientationPortrait
左:UIInterfaceOrientationLandscapeLeft
右:UIInterfaceOrientationLandscapeRight

而我在這function內最上面所印出來的log最後面帶的數字就是代表這方向的數字
想要使用只需要將這function加入在.m檔中的@implementation與@end中間
但.h檔必須繼承UIViewController

光是能轉換還是會遇上座標的問題
如果本來所使用都是固定座標就必須把座標系轉換一下(如下圖)

圖片來源:http://blog.sallarp.com/shouldautorotatetointerfaceorientation/



參考連結
iOS Developer Library
iOS Developer Library - UIApplication Class Reference
iOS Developer Library - Technical Note TN2244 Launching your Application in Landscape
http://blog.sallarp.com/shouldautorotatetointerfaceorientation/

iOS addSubview & removeFromSuperview

view的這概就有點像是
Photoshop的layer
Android的layout
Flash的symbol

app內可不像flash不想要這個symbol就丟進垃圾桶
要用時再直接從library拉出來
(當然全都使用Interface builder是有點類似啦)

要使用code來丟入場景中所使用的就是"addSubview"
如以下範例
[self.view addSubview:myView];


加入後會自動將myView的retainCount +1
如果原本的view不需要用上請記得釋放掉


那該怎樣知道現在這個View內有多少View
下面這範例會把內容全都println出來
NSLog(@"view = %@", [self.view subviews]);



知道有多少後該怎樣移除也是個重點
以下這就是將你指定的view移除
[myView removeFromSuperview];



那假設view中的按鈕很多看起來很礙眼想要一次移除
for(UIView *subview in [self.tabBarController.view subviews]) {
if([subview isKindOfClass:[UIButton class]]) {
NSLog(@"remove UIButton");
[subview removeFromSuperview];
} else {
// Do nothing - not a UIButton or subclass instance
}
}


isKindOdClass顧名思義就是找出跟他相同class的東西


參考資料
iOS Developer Library
iOS - UIView Class Reference
iOS - UIViewController Class Reference

Android - arrayAdapter refresh row

如果在固定大小的情況下還是建議使用BaseAdapter
但在大小未知的狀況下還是使用arrayAdapter比較適當
arrayAdapter有著四大常用的功能add(新增一筆到最後)、insert(新增一筆到指定位置)、remove(刪除最後一筆)、clear(全部清除)
但是每次新增的時候如果沒有讓getView作reDraw的動作並不會出現
或許新增的時候並不在畫面中沒有感覺
但新增或刪除在畫面中沒反應會造成使用上的困擾
廢話好像有點多...

如果只是想要做一般的reDraw
也就是將整個arrayAdapter刷新只需要使用下面這行即可
用了這個會全部重新繪製(也就是會跳回最開頭)
ListView.setAdapter(arrayAdapter);


如果想要保留在畫面中但是又更新請使用下面這兩行
用NotifyChange的方式告訴arrayAdapter資料更新
arrayAdapter.notifyDataSetChanged();
arrayAdapter.setNotifyOnChange(true);


此方法不僅在一般的ListView可以使用
在自動完成(AutoCompleteTextView)也一樣可以使用
做出類似google搜尋輸入時的建議搜尋


標題為啥要用英文定...因為我也不知道該怎樣比較適當的翻譯成中文一一

參考資料
Android Developer
Android - ArrayAdapter
Android - ListView

Android - Button in ListView

在Android內ListView是個相當常用的東西
相對於iOS來說也就是TableView
在iphone上面用tableView或Android的ListView上面加個按鈕都是相當容易的事
但是加了按鈕後該如何取得按鈕的事件(按下、放開、點兩下、長按、拖曳....等)在Android上面卻成了問題
當按鈕與ListView同時出現時只能夠偵測到按鈕的事件
而原本所使用的interfave或OnItemClickListener來偵測按鈕事件卻會失效

如下圖就是兩個同時存在的狀況(ListView & checkBox)


如果沒有解決辦法我也不會來po這篇XD
在Listview的interface內getView加上下面這行(以圖中這範例為例,使用checkBox)
checkBox.setFocusable(false);


但是光這樣設定還是會造成checkBox跟背景沒辦法融合
也就是點按鈕是按鈕,ListView的row是不同的地方
只要加上以下這行,把checkBox設定為不可按就搞定了
checkBox.setClickable(false);


在Android內的ListView、GridView與ListView內容都必須靠Adapter來作管理(iOS為NSArray或NSMutableArray)
只需要宣告上作修改就可以用另一種方式作呈現

參考資料
Android Developer
Android - ArrayAdapter
Android - ListView
Android - GridView