2012年9月15日 星期六

Cocos2D - CCSprite SetPosition

最近開始摸cocos2d
發現CCSprite類別的成員
如果要在init以外的地方重新設定位置
似乎不那麼容易

例如以下程式碼


clothe = [CCSprite spriteWithFile:@"clothe.png"];
clothe.position = ccp(100,100);
[self addChild:clothe];

這是在init初始的一個衣服成員
一開始就設定好在(100,100)的地方
之後我在別的函式想要重新SetPosition
卻發現無法運作 衣服不會移動位置

追查後發現解決方法
程式碼如下
[clothe stopAllActions];
[clothe setPosition:ccp(200,100)];

關鍵就是要先stopAllActions
以上

2012年8月25日 星期六

UIActionSheet Button location Error

之前一直為了UIActionSheet產生的button位置歪掉煩惱
像這張圖這樣

因為是小問題,所以沒有很認真去查
但實際上又是很煩惱的問題
今天終於搞定了
一般來說 我們要加入一個UIActionSheet會用以下程式碼
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil
                             delegate:self
                    cancelButtonTitle:NSLocalizedString(@"Cancel", @"Cancel")
               destructiveButtonTitle:NSLocalizedString(@"Logout", @"logout")
                    otherButtonTitles:nil];
actionSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[actionSheet showInView:self.view];
關鍵在最後一行
[actionSheet showInView:self.view];

實際上應該使用
[actionSheet showInView:[UIApplication sharedApplication].keyWindow];
要以整個window來看才正確 以上

2012年7月31日 星期二

NSMutableArray Sort


今天來分享一下NSMutableArray的排序方式

NSString *sortOrder = @"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz_0123456789";
            
            [array sortUsingComparator:^NSComparisonResult(id obj1, id obj2)
             {
                 char char1 = [(NSString *)obj1 characterAtIndex: 0];
                 char char2 = [(NSString *)obj2 characterAtIndex: 0];
                 
                 int index1;
                 for (index1 = 0; index1 < sortOrder.length; index1++)
                     if ([sortOrder characterAtIndex: index1] == char1)
                         break;
                 
                 int index2;
                 for (index2 = 0; index2 < sortOrder.length; index2++)
                     if ([sortOrder characterAtIndex: index2] == char2)
                         break;
                 
                 if (index1 < index2)
                     return NSOrderedAscending;
                 else if (index1 > index2)
                     return NSOrderedDescending;
                 else
                     return [(NSString *)obj1 compare: obj2 options: NSCaseInsensitiveSearch];
             }];

這樣Array就會照英文跟數字的方式來排序了

2012年7月30日 星期一

NSLOG without Date

今天來分享NSLOG的小東西
可以不秀出時間跟專案名稱
void IFPrint (NSString *format, ...)
{
    va_list args;
    va_start(args, format);
    
    fputs([[[[NSString alloc] initWithFormat:format arguments:args] autorelease] UTF8String], stdout);
    
    va_end(args);
}

2012年7月18日 星期三

Hold Button Event

這次來分享在ios上如何偵測長壓按鈕的訊息

因為ios本身storyboard沒有提供這個函式
所以用以下的程式碼來宣告一個UILongPressGestureRecognizer
用它來掌控時間到了要呼喚哪個函式
範例中是0.3秒
UILongPressGestureRecognizer * recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];    
        recognizer.minimumPressDuration = 0.3f;  
        [downButton addGestureRecognizer:recognizer];
        [recognizer release];

常見的問題是 會在select時呼叫自己宣告長壓時的函式
但那是錯誤的
要再判斷長壓的狀態才去執行該做的事情
所以以handleLongPress這個函式來判斷
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender
{ 
    if (sender.state == UIGestureRecognizerStateEnded)
    {
  //      NSLog(@"Long press Ended");
    }
    else
    {
        [self moveFastDown];
    }
}

UIGestureRecognizerStateEnded時不作事情
這是當長壓後放開按鈕時會觸發的狀態
所以最常看到的問題就是長壓後會觸發兩次
就是因為要正確的分辨狀態再執行
以上

2012年6月30日 星期六

Change UIActionSheet Style

 首先要記得繼承UIActionSheetDelegate

修改這個UIActionSheet的預設函式
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet
{
    // 設定UIActionSheet的backround圖片
    UIImage *theImage = [UIImage imageNamed:@"selectbg.png"];    
    theImage = [theImage stretchableImageWithLeftCapWidth:32 topCapHeight:32];
    CGSize theSize = actionSheet.frame.size;
    // draw the background image and replace layer content  
    UIGraphicsBeginImageContext(theSize);    
    [theImage drawInRect:CGRectMake(0, 0, theSize.width, theSize.height)];    
    theImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    [[actionSheet layer] setContents:(id)theImage.CGImage];
}
然後調整UIActionSheet彈出後的按鈕樣式
UIActionSheet* Action = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"加入" otherButtonTitles:nil, nil];
    
[[[Action valueForKey:@"_buttons"] objectAtIndex:0] setImage:[UIImage imageNamed:@"select_bt.png"] forState:UIControlStateNormal];
    
[[[busAction valueForKey:@"_buttons"] objectAtIndex:1] setImage:[UIImage imageNamed:@"select_bt2.png"] forState:UIControlStateNormal];
    
[Action showInView:self.view];

Combine two Image

-(UIImage*)mergeImage:(UIImage*)first withImage:(UIImage*)second
{
    // build merged size
    CGSize mergedSize = CGSizeMake(Main_Pic_Width * 2 + 10, Main_Pic_Height);
    
    // capture image context ref
    UIGraphicsBeginImageContext(mergedSize);
    
    //Draw images onto the context
    [first drawInRect:CGRectMake(0, 0, Main_Pic_Width, Main_Pic_Height)];
    [second drawInRect:CGRectMake(Main_Pic_Width + 10, 0, Main_Pic_Width, Main_Pic_Height)]; 
    
    // assign context to new UIImage
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    // end context
    UIGraphicsEndImageContext();
    
    return newImage;
}

ScreenShot to Image

首先要#import "QuartzCore/CALayer.h"跟QuartzCore.framework

.m檔程式碼如下
UIGraphicsBeginImageContext(CGRectMake(mainImageStartX, mainImageStartY, Main_Pic_Width, Main_Pic_Height).size);

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextConcatCTM(context, CGAffineTransformMakeTranslation(-mainImageStartX, -mainImageStartY));

[self.view.layer renderInContext:context];

g_StartImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

FMDB

首先當然是先下載FMDB的SDK

並且加入libsqlite3.0.dylib的framework
然後按照我的習慣會做成一個DB的singleton方便使用

首先是.h檔

#import <Foundation/Foundation.h>
#import "FMDatabase.h"

@interface DBData : NSObject
@property (nonatomic) FMDatabase* db;
  
+(DBData *)getInstance;   
-(FMDatabase *)loadDB:(NSString *)dbName;  
@end
接著是.m檔

#import "DBData.h"

@implementation DBData
@synthesize db;

static DBData *instance = nil;   
 
+(DBData *)getInstance   
{   
    @synchronized(self)    
    {   
        if (instance == nil)    
        {   
            instance = [[self alloc] init];   
        }   
    }   
    return instance;   
}   
   
-(FMDatabase* )loadDB:(NSString *)dbName   
{   
    NSURL *appUrl = [[[NSFileManager defaultManager] 
                      URLsForDirectory:NSDocumentDirectory 
                      inDomains:NSUserDomainMask] lastObject];
    NSString *dbPath = [[appUrl path] stringByAppendingPathComponent:@"MyDatabase.db"];   
    db = [FMDatabase databaseWithPath:dbPath];
    
    if (![db open]) {       
        NSLog(@"Could not open db");       
    }
    else
    {
        NSLog(@"open db Success");
    }       
    
    return db;   
}  
@end
都準備好了之後,就可以在程式的各處使用了
在要使用DB的.h加上這兩行

#import "DBData.h"

@interface Search : UIViewController 
{
    DBData *instance;    
    FMDatabase *db; 
}
要使用的.m檔如下,這是新增的範例
instance = [DBData getInstance];   
db = [instance loadDB:@"MyDatabase.db"];
            
FMResultSet *rs = [db executeQuery:@"SELECT name, description from MyDB WHERE name = ?",name];
            
if ([rs next])
{       
  NSString *name = [rs stringForColumn:@"name"];       
  NSString *description = [rs stringForColumn:@"description"];       
}
else
{         
  if(![db executeUpdate:@"INSERT INTO MyInfo (name, description) VALUES (?,?)", name, @"strong"])
  {
    [self displayAlertViewMsg:@"新增我的最愛失敗" andTitle:nil];
  }
  else
  {
    [self displayAlertViewMsg:@"新增我的最愛成功" andTitle:nil];
  }
}

GADBannerView

首先加入 iAd.framework

接著在.h檔設定如下

#import <UIKit/UIKit.h>
#import "GADBannerView.h"

@interface QuoteContentViewController : UIViewController<GADBannerViewDelegate>
{
    GADBannerView *bannerView_;
}
.m檔的初始設定,adUnitID更換成自己的廣告id即可

    // Create a view of the standard size at the bottom of the screen.
    float tabBarHeight = [[[super tabBarController] tabBar] frame].size.height;
    float tempHeight = 480.0f - GAD_SIZE_320x50.height - tabBarHeight - 15.0f;
    
    bannerView_ = [[GADBannerView alloc]
                   initWithFrame:CGRectMake(0.0,
                                            tempHeight,
                                            GAD_SIZE_320x50.width,
                                            GAD_SIZE_320x50.height)];
    
    // Specify the ad's "unit identifier." This is your AdMob Publisher ID. a14f05024e9e617
    bannerView_.adUnitID = @"a14f6a9cd715868";
    
    // Let the runtime know which UIViewController to restore after taking
    // the user wherever the ad goes and add it to the view hierarchy.
    bannerView_.rootViewController = self;
    bannerView_.delegate = self;
    [self.view addSubview:bannerView_];
    
    // Initiate a generic request to load it with an ad.
    [bannerView_ loadRequest:[GADRequest request]];
最後如果廣告要求成功的話,會在這個函式收到

- (void)adViewDidReceiveAd:(GADBannerView *)view
{
}

Viewcontrol title area color

// 設定最上方的標題列
UIColor* color = [[UIColor alloc]initWithRed:0.03 green:0.7 blue:0.31 alpha:1];
self.navigationController.navigationBar.tintColor = color;
    
UILabel *titleText = [[UILabel alloc] initWithFrame: CGRectMake(0, 0, 200, 28)]; 
titleText.backgroundColor = [UIColor clearColor]; 
[titleText setFont:[UIFont boldSystemFontOfSize:28.0]]; 
[titleText setTextColor:[UIColor whiteColor]];
[titleText setText:@"我的標題"]; 
self.navigationItem.titleView = titleText;

FaceBook - post article & photo on the wall

首先
當然是要加上FB的SDK

然後在.h檔設定如下

#import "FBConnect.h"

@interface AppDelegate : UIResponder <UIApplicationDelegate,FBDialogDelegate, FBSessionDelegate, FBLoginDialogDelegate,FBRequestDelegate>
{
}

// Facebook 
@property (nonatomic, retain) Facebook *facebook;
接下來到.m檔 MyAppId是自己在FaceBook申請的應用程式id
-(void)initFacebook
{
    // 初始化facebook
    facebook = [[Facebook alloc] initWithAppId:MyAppId andDelegate:self];
    
    // 記錄facebook登入的token
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) 
    {
        facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
        facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
    }
}
接下來修改AppDelegate的三個函式
-(void)applicationDidBecomeActive:(UIApplication *)application
{  
    [self extendAccessTokenIfNeeded];
}

-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url 
{
    [self handleOpenURL:url];
    return NO;
}

-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation 
{
    [self handleOpenURL:url];
    return NO;
}
補上其中呼叫的兩個函式handleOpenURL跟extendAccessTokenIfNeeded
-(void)extendAccessTokenIfNeeded
{
    [[self facebook] extendAccessTokenIfNeeded]; 
}

-(BOOL)handleOpenURL:(NSURL *)url
{
    return [self.facebook handleOpenURL:url];
}
取得授權跟login
-(void)loginFacebook
{
    if(![facebook isSessionValid])
    {
        //取得相關授權
        NSArray *permissions = [[NSArray alloc] initWithObjects:
                                @"user_likes",
                                @"read_stream",
                                @"user_birthday",
                                @"publish_stream",
                                @"offline_access",
                                @"user_status",
                                nil];
        [self.facebook authorize:permissions];
    }
    else
    {
        [self fbDidLogin];
    }
}
login跟logout的內容
- (void)fbDidLogin 
{
    NSLog(@"fbDidLogin");
    [self storeAuthData:[[self facebook] accessToken] expiresAt:[[self facebook] expirationDate]];
}

- (void)fbDidLogout 
{
    NSLog(@"fbDidLogout");
    
    // Remove saved authorization information if it exists and it is
    // ok to clear it (logout, session invalid, app unauthorized)
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults removeObjectForKey:@"FBAccessTokenKey"];
    [defaults removeObjectForKey:@"FBExpirationDateKey"];
    [defaults synchronize];
}
接下來重頭戲來了,將文章跟照片post上FB
-(void)postFacebook
{
    NSLog(@"fbDidLogin");
    [self storeAuthData:[[self facebook] accessToken] expiresAt:[[self facebook] expirationDate]];
    
    currentAPICall = kAPIGraphUserPost;
    
    NSString *sMessage = [[NSString alloc] initWithString:[NSString stringWithFormat:@"3我要潑的訊息"]];
    
        NSMutableDictionary * params2 = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                         g_FBPostImage, @"picture",sMessage,@"message",
                                         nil];
    
        [facebook requestWithGraphPath:@"me/photos" 
                             andParams:params2 
                         andHttpMethod:@"POST" 
                           andDelegate:self];
}
如果不要潑圖片,只要潑訊息,可以將me/photos改成me/feed,然後g_FBPostImage, @"picture",這段拿掉即可
最後補上一些FB預設的函式,用以捕捉訊息
- (void)apiFQLIMe 
{
    // Using the "pic" picture since this currently has a maximum width of 100 pixels
    // and since the minimum profile picture size is 180 pixels wide we should be able
    // to get a 100 pixel wide version of the profile picture
    NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   @"SELECT uid, name, pic FROM user WHERE uid=me()", @"query",
                                   nil];
    [[self facebook] requestWithMethodName:@"fql.query"
                                 andParams:params
                             andHttpMethod:@"POST"
                               andDelegate:self];
}

- (NSDictionary *)parseURLParams:(NSString *)query {
    
 NSArray *pairs = [query componentsSeparatedByString:@"&"];
 NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
 for (NSString *pair in pairs) {
  NSArray *kv = [pair componentsSeparatedByString:@"="];
  NSString *val =
        [[kv objectAtIndex:1]
         stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        
  [params setObject:val forKey:[kv objectAtIndex:0]];
 }
    return params;
}


- (void)storeAuthData:(NSString *)accessToken expiresAt:(NSDate *)expiresAt {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:accessToken forKey:@"FBAccessTokenKey"];
    [defaults setObject:expiresAt forKey:@"FBExpirationDateKey"];
    [defaults synchronize]; 
}

- (void)fbSessionInvalidated 
{
    NSLog(@"fbSessionInvalidated");
    
    UIAlertView *alertView = [[UIAlertView alloc]
                              initWithTitle:@"Auth Exception"
                              message:@"Your session has expired."
                              delegate:nil
                              cancelButtonTitle:@"OK"
                              otherButtonTitles:nil,
                              nil];
    [alertView show];
    [self fbDidLogout];
}


#pragma mark - FBRequestDelegate Methods
/**
 * Called when the Facebook API request has returned a response. This callback
 * gives you access to the raw response. It's called before
 * (void)request:(FBRequest *)request didLoad:(id)result,
 * which is passed the parsed response object.
 */
- (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response 
{
    NSLog(@"received response");
}

- (void)request:(FBRequest *)request didLoad:(id)result 
{
    NSLog(@"request:didLoad");
    
    haveFbRequest = false;
    
    if ([result isKindOfClass:[NSArray class]] && ([result count] > 0))
    {
        result = [result objectAtIndex:0];
    }
    
    UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"成功分享到facebook了!" message:nil delegate:self cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
    
    [alertView show];
}

- (void)request:(FBRequest *)request didFailWithError:(NSError *)error
{
    NSLog(@"request fail");
    NSLog(@"Error message: %@", [[error userInfo] objectForKey:@"error_msg"]);
}




#pragma mark - FBDialogDelegate Methods

/**
 * Called when a UIServer Dialog successfully return. Using this callback
 * instead of dialogDidComplete: to properly handle successful shares/sends
 * that return ID data back.
 */
- (void)dialogCompleteWithUrl:(NSURL *)url 
{
    NSLog(@"dialogCompleteWithUrl.");
    
    if (![url query]) 
    {
        NSLog(@"User canceled dialog or there was an error");
        return;
    }
    
}