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