ActionBarのロゴの表示/非表示を切り替える。

最近はActionBarを利用していないアプリはめっきり見かけなくなったこの頃。

ActionBarを利用してて、ActionBar.setLogo メソッドを利用して、Fragmentごとにロゴを表示したり、非表示にしたりしたいと思い色々調べたら、なかなかうまく表示されなかったので、まとめておく。

動作

ホーム画面だけロゴを出す。左メニュー(Navigation Drawer)を利用してFragmentを切り替えた時に、ホーム画面以外の場合はアイコンとページ名をActionBarに表示させる。

画面イメージ

f:id:sharakova:20140628171159p:plain

f:id:sharakova:20140628171209p:plain

Activity

public class BaseActivity extends FragmentActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getActionBar().setDisplayShowHomeEnabled(true);
        getActionBar().setDisplayShowCustomEnabled(true);
        getActionBar().setLogo(R.drawable.logo_white); // ホーム画面のロゴ
        getActionBar().setIcon(R.drawable.icon_menu_popular); // ホーム以外で表示するアイコン
        getActionBar().setDisplayUseLogoEnabled(false); // ロゴを非表示 
    }
}

ホーム画面のFragment

setDisplayUseLogoEnabledをtrueにすると、アイコンは自然と消えロゴだけが表示されるようだ。

final class HomeFragment extends Fragment {
    @Override
    public void onResume() {
        super.onResume();
        getActivity().getActionBar().setTitle("");   // タイトル空
        getActivity().getActionBar().setDisplayUseLogoEnabled(true); // ロゴを表示
    }
}

その他 Fragment

setDisplayUseLogoEnabledで、ロゴを非表示にするだけで、Activityでセットしたアイコンが表示される。

final class PopularFragment extends Fragment {
    @Override
    public void onResume() {
        super.onResume();
        getActivity().getActionBar().setTitle("注目ユーザー");   // タイトル
        getActivity().getActionBar().setDisplayUseLogoEnabled(false); // ロゴを非表示
    }
}

いろいろアプリを作った上で、APIの実装をまとめ

APIの設計で単純な配列返すAPIでも、オブジェクトで返してげた方がよさそう。
Jsonのフォーマットとして、下記でも問題ないんですが、後々困る。

例)/list/brands.json

[
	{
		'keyword': 'ユニクロ',
		'rank': 1
	}
	{
		'keyword': 'しまむら',
		'rank': 2
	}
	{
		'keyword': 'H&M',
		'rank': 3
	}
]

あとで、このAPIをたたく画面で追加要素とかいろいろ出てきます。
画面のタイトルをAPIから返したいとか、画像をつけたいなど・・・
一度APIとアプリをリリースしてしまうと、アプリのアップデートが終わるまでJsonにオブジェクトは足せても、フォーマットは変えられない。

{
	brands: [
		{
			'keyword': 'ユニクロ',
			'rank': 1
		}
		{
			'keyword': 'しまむら',
			'rank': 2
		}
		{
			'keyword': 'H&M',
			'rank': 3
		}
	]
}


あとから、popularやnoticeのオブジェクト追加しても古いアプリでも問題なく動作する。

{
	popular: {
		pic_id : 1,
		thumbnail: 'http://example.com/thumbnail.jpg',
		description: 'なんとかかんとか'
	}
	notice: {
		notice_id: 12,
		title: '運営からのお知らせ'
	}
	brands: [
		{
			'keyword': 'ユニクロ',
			'rank': 1
		}
		{
			'keyword': 'しまむら',
			'rank': 2
		}
		{
			'keyword': 'H&M',
			'rank': 3
		}
	]
}

PHP PDOを利用したMySQLのINSERTとSELECTサンプル

自分のメモです。PHP 5.3.3でPDOを利用してデータベースの接続サンプルを書きました。
PDOを利用して、ローカルにたてたMySQLに接続し、insert時にはプリペアドステートメントプレースホルダーを利用しています。

<?php
try {
    mb_internal_encoding('UTF-8');
    $data = array(
        array('name' => 'カレー', 'price' => 750),
        array('name' => 'オムライス', 'price' => 700),
        array('name' => '天ぷら', 'price' => 300)
    );
    $dbh = new PDO('mysql:dbname=sample_db_lv2;host=localhost', 'userid', 'password');
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $insert = 'INSERT INTO menus (name, price) VALUES (:name, :price)';
    $sth = $dbh->prepare($insert);
    foreach ($data as $row) {
        $sth->execute($row);
    }

    $select = 'SELECT * FROM menus ORDER BY id DESC';
    $sth = $dbh->prepare($select);
    $sth->execute();
    $red = $sth->fetchAll();

    foreach ($red as $row) {
        echo "id:\t" . $row['id'] . "\n";
        echo "name:\t" . $row['name'] . "\n";
        echo "price:\t" . $row['price'] . "\n\n";
    }
} catch (PDOException $e) {
    var_dump($e->getMessage());
}

Nexus 7でGoogle Play Booksを試す

先日、日本でもGoogleNexus 7の発売開始され、同時にPlayブックスのサービスも開始されたので利用してみた。

Nexus 7に関しては、Google I/Oでもらったモノであり、日本で発売しているものと若干違うかもしれません。


Nexus 7の本体は男の手でなんとか片手で持てるサイズで、本体の横にある音量ボタンで、ページ遷移する事ができます。

実は、片手で本が読めるって画期的!!
本物の本ですら片手ではページをめくれないので、なかなかスムーズ。

iPadのようにわざわざスライドする必要がないですし、本体の重さが340gと軽く片手で持っていても疲れません。寝ながらだったり、電車のつり革につかまりながら片手で本を読めます。


しかし、技術書など販売されているがその多くがNexus 7の画面では小さい印象を受ける。文字が小さくて読めない。
(画面の解像度もRetinaに比べる悪いのもあると思う)
しかも、多くの技術書がスキャンされた本のようで、検索などもクソ同然ですし、拡大してもフォントは汚いです。


参考書などはiPadの方が読み易いですが、漫画・小説などは、ほんとうに丁度いいサイズ!
まだまだ読みたい本がないので、今後増える事を願う。。。

一つ、希望をいうと『音量を下げるボタン=次のページ』に統一して欲しい。本によって逆のボタンになっていたりするので使いづらい。

Objective-C storyboardを利用せずに画面遷移

Mountain lionとXCode 4.4を利用。
iPhoneアプリの開発で、iOS4を対応したかったため、Storyboardを利用せずに、
xibを利用しつつ画面遷移させるコードメモ。

- (IBAction)onClickNextButton:(id)sender {
    NextViewController *nextView = [[NextViewController alloc] init];
    nextView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:nextView animated:YES];
}

facebookのいいねボタンでウォールに表示される画像を変更

facebookのいいねボタンを押された場合に、ウォールに設定される画像はfacebook側で勝手に選んだ画像を利用され、意図しない画像が選ばれることがあったので、デベロッパーサイトに書かれている、metaタグを指定することで回避ができる。

http://developers.facebook.com/docs/reference/plugins/like/



ただし、metaタグを指定してもすぐには反映されない。
どうも画像データなどをキャッシュしているようだ・・・


そういう場合は、キャッシュを消すページも存在しているので、下のページからURLを入力すると画像データが更新されます。ほかにも、タグの警告なども表示されるので便利。

https://developers.facebook.com/tools/debug

Objective-C UIImageをアスペク比を保ったままリサイズ

UIImageのアスペクト比を保ったまま、画像をリサイズする。

引数で渡す、NIIntegerでsizeを指定したサイズ未満に画像をリサイズします。
縦長い画像はheightが、横長画像の場合はがwidthが指定したサイズになります。

参考プログラム
http://stackoverflow.com/questions/1282830/uiimagepickercontroller-uiimage-memory-and-more

#import "ImageResize.h"

@implementation ImageResize

#define radians( degrees ) ( degrees * M_PI / 180 )

+ (UIImage*)resizeAspectFit:(UIImage*)sourceImage size:(NSInteger)size
{
    
    CGImageRef imageRef = [sourceImage CGImage];
    size_t w = CGImageGetWidth(imageRef);
    size_t h = CGImageGetHeight(imageRef);
    CGFloat targetWidth, targetHeight;
    
    if (w>h) {
        targetWidth = size;
        targetHeight = h * targetWidth / w;
    } else {
        targetWidth = size;
        targetHeight = w * targetWidth / h;
    }

    NSLog(@"image resize w=%ld h=%ld -> w=%f h=%f", w, h, targetWidth, targetHeight);

    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);
    
    if (bitmapInfo == kCGImageAlphaNone) {
        bitmapInfo = kCGImageAlphaNoneSkipLast;
    }
    
    CGContextRef bitmap;
    
    if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {
        bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
        
    } else {
        bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
        
    }   
    
    if (sourceImage.imageOrientation == UIImageOrientationLeft) {
        CGContextRotateCTM (bitmap, radians(90));
        CGContextTranslateCTM (bitmap, 0, -targetHeight);
        
    } else if (sourceImage.imageOrientation == UIImageOrientationRight) {
        CGContextRotateCTM (bitmap, radians(-90));
        CGContextTranslateCTM (bitmap, -targetWidth, 0);
        
    } else if (sourceImage.imageOrientation == UIImageOrientationUp) {
        // NOTHING
    } else if (sourceImage.imageOrientation == UIImageOrientationDown) {
        CGContextTranslateCTM (bitmap, targetWidth, targetHeight);
        CGContextRotateCTM (bitmap, radians(-180.));
    }
    
    CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    UIImage* newImage = [UIImage imageWithCGImage:ref];
    
    CGContextRelease(bitmap);
    CGImageRelease(ref);
    
    return newImage; 
}

@end