SlideShare ist ein Scribd-Unternehmen logo
1 von 15
Downloaden Sie, um offline zu lesen
意外と苦労する、一部の画面のみ
ランドスケープ表示を許容する方法
2015/05/13【第17回】potatotips(iOS/Android開発Tips共有会)
自己紹介
• Twitter: @_mono, Facebook: mono0926
• みんなでつくるスポーツニュースアプリ『Player!』
• 先月リリースして日々アップデート中
• LINEクリエイターズスタンプ作って販売中
• http://bit.ly/love-stamp
• 昨年6月からずっとSwift触ってます
一部の画面だけ回転(ランドスケープ表示)を
許容させるのつらい
• 全部許容 or 一部の画面だけ非許容は簡単
• Stackoverflowやブログなどで色々情報あるが、
それぞれ苦労している感があるし、画面構成に
よってはうまく動かなかったりでつらい
• カテゴリ拡張でオーバーライド

もどきする方法微妙(後述)
愚直な方法
• AppDelegateのsupportedInterfaceOrientationsForWindowにて縦横許容
• 縦固定にしたい各UIViewControllerのsupportedInterfaceOrientationsで
回転を制限
• ルートのViewControllerの設定が効くので、UINavigationControllerや
UITabBarControllerなど使っている場合はわざわざ継承して、かつ現
在表示中のViewControllerを見て適切な値を返す
• わざわざ継承するの面倒
• 漏れなく実装するのが大変・デグりやすい
統一的な方法として
ちょくちょく見かけるやり方
• UIViewControllerカテゴリ拡張でオーバーライドもどき
• func supportedInterfaceOrientations() -> Int などを
• カテゴリ拡張は現状、挙動的には以下の順に優先されるが、仕様的には不定
なので極力避けたい
1. カスタムクラスでの実装
2. カテゴリによるクラス拡張での実装
3. デフォルト実装(プロジェクト設定通りになる)
• selfがルートのViewControllerだったら表示中のViewControllerを っていっ
て、そこに定義してある実装を返す
AppDelegateの
application:supportedInterfaceOrientationsForWindow:
に処理を集約するやり方
• 実装している場合、まずこれが呼ばれるので、その時の画面
状態によって回転可能な向きを絞るようにすれば
AppDelegateに処理をまとめられる
• アプリの状態はどのように判別する??
アプリの状態は
どのように判別するか
• rootのViewControllerから、最前面の画面を る
• selectedViewController
• topViewController
• presentedViewControler
• visibleViewController
• アプリの画面構成に依存してしまう
• がんばれば汎用的にも書けるかも?
今回やってみた方法: Aspectsによ
るMethod Swizzling
• Aspectsとは
• Method Swizzlingのラッパーライブラリ
• 特定クラスインスタンスのメソッド実行の前後に処理を挟んだり、すり替えたりが簡単に出来る
• GitHubのStarも1600を超えている信頼出来そうなライブラリ
• Google Analyticsの埋め込みなどにも便利
• Method Swizzlingもトリッキーな方法ではあるが、カテゴリ拡張でのオーバーライドより筋が良い
具体的な実装
• 縦横回転許容するViewControllerにてallowRotationプロパティを
trueにする
• allowRotationプロパティは、カテゴリ拡張によって定義した
Associated Object
private var allowRotationKey: UInt8 = 0
extension UIViewController {
var allowRotation: Bool {
get { return (objc_getAssociatedObject(self, &allowRotationKey) as? Bool) ?? false }
set { objc_setAssociatedObject(self, &allowRotationKey, newValue, UInt(OBJC_ASSOCIATION_RETAIN)) }
}
}
class ModalViewController1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
allowRotation = true
}
}
具体的な実装
• AppDelegateでAspectsを使ってViewController
に回転周りの実装を注入
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var allowRotation = false
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject:
AnyObject]?) -> Bool {
// 起動時にAspectsの設定
hookForRotation()
return true
}
/** 適切なタイミングで回転をハンドリング */
private func hookForRotation() {
// 次のスライドで
}
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int
{
// 常にに横許容
return Int(UIInterfaceOrientationMask.AllButUpsideDown.rawValue)
}
}
具体的な実装
/** 適切なタイミングで回転をハンドリング */
private func hookForRotation() {
ObjcHelper.aspect_viewControllerHookSelector("viewWillAppear:", withOptions: .PositionBefore, error: nil) { info in
let vc = info.instance() as UIViewController
self.allowRotation = vc.allowRotation
}
// 非表示時にAppDelegateのallowRotationを切り替え
ObjcHelper.aspect_navigationControllerHookSelector("popViewControllerAnimated:", withOptions: .PositionBefore,
error: nil) { info in
let vc = info.instance() as UINavigationController
let vcs = vc.viewControllers
self.allowRotation = (vcs[vcs.count - 2] as UIViewController).allowRotation
}
ObjcHelper.aspect_viewControllerHookSelector("dismissViewControllerAnimated:completion:",
withOptions: .PositionBefore, error: nil) { info in
let vc = info.instance() as UIViewController
if let presentingViewController = vc.presentingViewController {
self.allowRotation = presentingViewController.allowRotation
}
}
// supportedInterfaceOrientationsの実装をすり替え
ObjcHelper.aspect_viewControllerHookSelector("supportedInterfaceOrientations", withOptions: .PositionInstead,
error: nil) { info in
let vc = info.instance() as UIViewController
let invocation = info.originalInvocation()
var ret = Int(self.allowRotation ? UIInterfaceOrientationMask.AllButUpsideDown.rawValue :
UIInterfaceOrientationMask.Portrait.rawValue)
invocation.setReturnValue(&ret)
}
}
iPad, iOS 6/7は?
• 適用したプロジェクトがiPhone・iOS8オンリー
なので、あまり深くチェック出来ていませんが、
現状 +アレンジ程度で正常に動くようになると思
います
• iOS5以前は回転の仕組みが違うので別対応必要
• ぐぐる時もこの古い情報がまだけっこう引っか
かるので注意
アレンジ
• 一部の特殊な画面では、さらに追加実装が必要になるが、
それに耐えうるか?
• 例: WebViewでの動画フルスクリーン再生
• YouTubeなどの動画が配置されている画面で、再生ボタン
を押すとフルスクリーンになるが、その時だけ回転を許
容したい
• AppDelegateを弄るだけで対応出来た(最後のスライド
に載せたレポジトリのソース参照)
その他回転周りの注意点
• プロジェクト設定で縦横許容すると、ランドスケープ対応端末(iPhone 6 Plusなど)で横
画面にして起動するとスプラッシュ画面が真っ黒になる
• 全体がランドスケープ対応の場合:
• ランドスケープ用のスプラッシュ画像を配置
• 非対応の場合:
• プロジェクト設定は縦のみにして、AppDelegateの
supportedInterfaceOrientationsForWindowにて縦横許容とすると、起動時にちゃ
んと縦用のスプラッシュ画面が出る
ソースコード
• https://github.com/mono0926/ios-rotation-sandbox
• 開発中のアプリは副作用があってハマったり、ビルド時
間かかったりするので、検証環境を用意すると る
• ビルド時間はSwift 1.2のインクリメントビルドで、
ちょっとした変更後のビルドは体感10倍くらいになっ
たものの
• 今回紹介した方法をベースにアレンジする場合などにもご
活用ください

Weitere ähnliche Inhalte

Was ist angesagt?

Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方Yoshifumi Kawai
 
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]DeNA
 
AirLab導入でテストコストの大幅削減と品質向上! 数十台の端末を一斉に全自動テストできる社内DeviceFarmについてご紹介
AirLab導入でテストコストの大幅削減と品質向上! 数十台の端末を一斉に全自動テストできる社内DeviceFarmについてご紹介AirLab導入でテストコストの大幅削減と品質向上! 数十台の端末を一斉に全自動テストできる社内DeviceFarmについてご紹介
AirLab導入でテストコストの大幅削減と品質向上! 数十台の端末を一斉に全自動テストできる社内DeviceFarmについてご紹介KLab Inc. / Tech
 
やさしいGitの内部構造 - yapcasia2013
やさしいGitの内部構造 - yapcasia2013やさしいGitの内部構造 - yapcasia2013
やさしいGitの内部構造 - yapcasia2013DQNEO
 
十分鐘讓程式人搞懂雲端平台與技術
十分鐘讓程式人搞懂雲端平台與技術十分鐘讓程式人搞懂雲端平台與技術
十分鐘讓程式人搞懂雲端平台與技術鍾誠 陳鍾誠
 
UnityでUI開発を高速化した件
UnityでUI開発を高速化した件UnityでUI開発を高速化した件
UnityでUI開発を高速化した件Grenge, Inc.
 
通信対戦ゲームを作った話
通信対戦ゲームを作った話通信対戦ゲームを作った話
通信対戦ゲームを作った話mipsparc
 
three.jsを「遅い」と思わせないデータの扱い方
three.jsを「遅い」と思わせないデータの扱い方three.jsを「遅い」と思わせないデータの扱い方
three.jsを「遅い」と思わせないデータの扱い方jey en
 
機械学習 / Deep Learning 大全 (4) GPU編
機械学習 / Deep Learning 大全 (4) GPU編機械学習 / Deep Learning 大全 (4) GPU編
機械学習 / Deep Learning 大全 (4) GPU編Daiyu Hatakeyama
 
WPF開発での陥りやすい罠
WPF開発での陥りやすい罠WPF開発での陥りやすい罠
WPF開発での陥りやすい罠Sho Okada
 
Linux女子会 - お仕事メリハリ術♪(プロセススケジューラ編)
Linux女子会 - お仕事メリハリ術♪(プロセススケジューラ編)Linux女子会 - お仕事メリハリ術♪(プロセススケジューラ編)
Linux女子会 - お仕事メリハリ術♪(プロセススケジューラ編)Yahoo!デベロッパーネットワーク
 
Try new transport protocol SRT (ver. 2)
Try new transport protocol SRT  (ver. 2)Try new transport protocol SRT  (ver. 2)
Try new transport protocol SRT (ver. 2)Tetsuyuki Kobayashi
 
[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개MinGeun Park
 
ゲームアプリの数学@GREE GameDevelopers' Meetup
ゲームアプリの数学@GREE GameDevelopers' Meetupゲームアプリの数学@GREE GameDevelopers' Meetup
ゲームアプリの数学@GREE GameDevelopers' Meetupgree_tech
 
アプリの鍵が消える時_Droid kaigi2018
アプリの鍵が消える時_Droid kaigi2018アプリの鍵が消える時_Droid kaigi2018
アプリの鍵が消える時_Droid kaigi2018ak_shio_555
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理Norishige Fukushima
 
GUI アプリケーションにおける MVC
GUI アプリケーションにおける MVCGUI アプリケーションにおける MVC
GUI アプリケーションにおける MVCYu Nobuoka
 
ゲームエンジンの中の話
ゲームエンジンの中の話ゲームエンジンの中の話
ゲームエンジンの中の話Masayoshi Kamai
 
ゲームの仕様書を書こうまとめ
ゲームの仕様書を書こうまとめゲームの仕様書を書こうまとめ
ゲームの仕様書を書こうまとめSugimoto Chizuru
 

Was ist angesagt? (20)

Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
 
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
スマホゲームのチート手法とその対策 [DeNA TechCon 2019]
 
AirLab導入でテストコストの大幅削減と品質向上! 数十台の端末を一斉に全自動テストできる社内DeviceFarmについてご紹介
AirLab導入でテストコストの大幅削減と品質向上! 数十台の端末を一斉に全自動テストできる社内DeviceFarmについてご紹介AirLab導入でテストコストの大幅削減と品質向上! 数十台の端末を一斉に全自動テストできる社内DeviceFarmについてご紹介
AirLab導入でテストコストの大幅削減と品質向上! 数十台の端末を一斉に全自動テストできる社内DeviceFarmについてご紹介
 
やさしいGitの内部構造 - yapcasia2013
やさしいGitの内部構造 - yapcasia2013やさしいGitの内部構造 - yapcasia2013
やさしいGitの内部構造 - yapcasia2013
 
十分鐘讓程式人搞懂雲端平台與技術
十分鐘讓程式人搞懂雲端平台與技術十分鐘讓程式人搞懂雲端平台與技術
十分鐘讓程式人搞懂雲端平台與技術
 
UnityでUI開発を高速化した件
UnityでUI開発を高速化した件UnityでUI開発を高速化した件
UnityでUI開発を高速化した件
 
通信対戦ゲームを作った話
通信対戦ゲームを作った話通信対戦ゲームを作った話
通信対戦ゲームを作った話
 
three.jsを「遅い」と思わせないデータの扱い方
three.jsを「遅い」と思わせないデータの扱い方three.jsを「遅い」と思わせないデータの扱い方
three.jsを「遅い」と思わせないデータの扱い方
 
機械学習 / Deep Learning 大全 (4) GPU編
機械学習 / Deep Learning 大全 (4) GPU編機械学習 / Deep Learning 大全 (4) GPU編
機械学習 / Deep Learning 大全 (4) GPU編
 
WPF開発での陥りやすい罠
WPF開発での陥りやすい罠WPF開発での陥りやすい罠
WPF開発での陥りやすい罠
 
Linux女子会 - お仕事メリハリ術♪(プロセススケジューラ編)
Linux女子会 - お仕事メリハリ術♪(プロセススケジューラ編)Linux女子会 - お仕事メリハリ術♪(プロセススケジューラ編)
Linux女子会 - お仕事メリハリ術♪(プロセススケジューラ編)
 
Try new transport protocol SRT (ver. 2)
Try new transport protocol SRT  (ver. 2)Try new transport protocol SRT  (ver. 2)
Try new transport protocol SRT (ver. 2)
 
[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개[160402_데브루키_박민근] UniRx 소개
[160402_데브루키_박민근] UniRx 소개
 
ゲームアプリの数学@GREE GameDevelopers' Meetup
ゲームアプリの数学@GREE GameDevelopers' Meetupゲームアプリの数学@GREE GameDevelopers' Meetup
ゲームアプリの数学@GREE GameDevelopers' Meetup
 
アプリの鍵が消える時_Droid kaigi2018
アプリの鍵が消える時_Droid kaigi2018アプリの鍵が消える時_Droid kaigi2018
アプリの鍵が消える時_Droid kaigi2018
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理
 
GUI アプリケーションにおける MVC
GUI アプリケーションにおける MVCGUI アプリケーションにおける MVC
GUI アプリケーションにおける MVC
 
ゲームエンジンの中の話
ゲームエンジンの中の話ゲームエンジンの中の話
ゲームエンジンの中の話
 
MVVM入門
MVVM入門MVVM入門
MVVM入門
 
ゲームの仕様書を書こうまとめ
ゲームの仕様書を書こうまとめゲームの仕様書を書こうまとめ
ゲームの仕様書を書こうまとめ
 

Andere mochten auch

殺しても死なないアプリ 〜Core Bluetooth の「状態の保存と復元」機能〜
殺しても死なないアプリ 〜Core Bluetooth の「状態の保存と復元」機能〜殺しても死なないアプリ 〜Core Bluetooth の「状態の保存と復元」機能〜
殺しても死なないアプリ 〜Core Bluetooth の「状態の保存と復元」機能〜Shuichi Tsutsumi
 
SQLiteDatabaseを無理矢理覗く
SQLiteDatabaseを無理矢理覗くSQLiteDatabaseを無理矢理覗く
SQLiteDatabaseを無理矢理覗くTakao Sumitomo
 
AppStore申請を一式まるっと自動化する
AppStore申請を一式まるっと自動化するAppStore申請を一式まるっと自動化する
AppStore申請を一式まるっと自動化するTomoki Hasegawa
 
Google Maps を使ったアプリを作ってみた
Google Maps を使ったアプリを作ってみたGoogle Maps を使ったアプリを作ってみた
Google Maps を使ったアプリを作ってみたShigeki Yamato
 
KotlinつかってQiitaクライアント作った時の話
KotlinつかってQiitaクライアント作った時の話KotlinつかってQiitaクライアント作った時の話
KotlinつかってQiitaクライアント作った時の話shinnosuke kugimiya
 
Swift - Result<t>型で結果を返すのは邪道か,王道か
Swift - Result<t>型で結果を返すのは邪道か,王道かSwift - Result<t>型で結果を返すのは邪道か,王道か
Swift - Result<t>型で結果を返すのは邪道か,王道かYuichi Yoshida
 
Isucon makers casual talks
Isucon makers casual talksIsucon makers casual talks
Isucon makers casual talksMasahiro Nagano
 
How to measure UIView position on Native App
How to measure UIView position on Native AppHow to measure UIView position on Native App
How to measure UIView position on Native AppDaisuke Yamashita
 
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)Hiroyuki Kusu
 
RealmとApp Extensionのガイダンス/Realm meetup vol.6
RealmとApp Extensionのガイダンス/Realm meetup vol.6RealmとApp Extensionのガイダンス/Realm meetup vol.6
RealmとApp Extensionのガイダンス/Realm meetup vol.6Yuta Hoshino
 
既存プロジェクトにSwiftLintを導入した話
既存プロジェクトにSwiftLintを導入した話既存プロジェクトにSwiftLintを導入した話
既存プロジェクトにSwiftLintを導入した話akatsuki174
 
勉強会のこちら側とあちら側
勉強会のこちら側とあちら側勉強会のこちら側とあちら側
勉強会のこちら側とあちら側Tomoki Hasegawa
 
あなたのオブジェクト指向はオブジェクト指向ではないかもしれない
あなたのオブジェクト指向はオブジェクト指向ではないかもしれないあなたのオブジェクト指向はオブジェクト指向ではないかもしれない
あなたのオブジェクト指向はオブジェクト指向ではないかもしれない康廣 木目沢
 
#yidev 第25回勉強会 オープニング
#yidev 第25回勉強会 オープニング#yidev 第25回勉強会 オープニング
#yidev 第25回勉強会 オープニングTomohiro Kumagai
 
みんなで Swift 復習会での談笑用スライド – 3rd #minna_de_swift
みんなで Swift 復習会での談笑用スライド – 3rd #minna_de_swiftみんなで Swift 復習会での談笑用スライド – 3rd #minna_de_swift
みんなで Swift 復習会での談笑用スライド – 3rd #minna_de_swiftTomohiro Kumagai
 
App extension for iOS
App extension for iOSApp extension for iOS
App extension for iOStoyship
 
JVM言語を使ってみようの歌
JVM言語を使ってみようの歌JVM言語を使ってみようの歌
JVM言語を使ってみようの歌YujiSoftware
 
Java in the Past, Java in the Future
Java in the Past, Java in the FutureJava in the Past, Java in the Future
Java in the Past, Java in the FutureYuichi Sakuraba
 

Andere mochten auch (20)

殺しても死なないアプリ 〜Core Bluetooth の「状態の保存と復元」機能〜
殺しても死なないアプリ 〜Core Bluetooth の「状態の保存と復元」機能〜殺しても死なないアプリ 〜Core Bluetooth の「状態の保存と復元」機能〜
殺しても死なないアプリ 〜Core Bluetooth の「状態の保存と復元」機能〜
 
SQLiteDatabaseを無理矢理覗く
SQLiteDatabaseを無理矢理覗くSQLiteDatabaseを無理矢理覗く
SQLiteDatabaseを無理矢理覗く
 
AppStore申請を一式まるっと自動化する
AppStore申請を一式まるっと自動化するAppStore申請を一式まるっと自動化する
AppStore申請を一式まるっと自動化する
 
Google Maps を使ったアプリを作ってみた
Google Maps を使ったアプリを作ってみたGoogle Maps を使ったアプリを作ってみた
Google Maps を使ったアプリを作ってみた
 
KotlinつかってQiitaクライアント作った時の話
KotlinつかってQiitaクライアント作った時の話KotlinつかってQiitaクライアント作った時の話
KotlinつかってQiitaクライアント作った時の話
 
Swift - Result<t>型で結果を返すのは邪道か,王道か
Swift - Result<t>型で結果を返すのは邪道か,王道かSwift - Result<t>型で結果を返すのは邪道か,王道か
Swift - Result<t>型で結果を返すのは邪道か,王道か
 
Isucon makers casual talks
Isucon makers casual talksIsucon makers casual talks
Isucon makers casual talks
 
How to measure UIView position on Native App
How to measure UIView position on Native AppHow to measure UIView position on Native App
How to measure UIView position on Native App
 
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)
 
RealmとApp Extensionのガイダンス/Realm meetup vol.6
RealmとApp Extensionのガイダンス/Realm meetup vol.6RealmとApp Extensionのガイダンス/Realm meetup vol.6
RealmとApp Extensionのガイダンス/Realm meetup vol.6
 
Xcode tips
Xcode tipsXcode tips
Xcode tips
 
既存プロジェクトにSwiftLintを導入した話
既存プロジェクトにSwiftLintを導入した話既存プロジェクトにSwiftLintを導入した話
既存プロジェクトにSwiftLintを導入した話
 
ゲンバのSwift
ゲンバのSwiftゲンバのSwift
ゲンバのSwift
 
勉強会のこちら側とあちら側
勉強会のこちら側とあちら側勉強会のこちら側とあちら側
勉強会のこちら側とあちら側
 
あなたのオブジェクト指向はオブジェクト指向ではないかもしれない
あなたのオブジェクト指向はオブジェクト指向ではないかもしれないあなたのオブジェクト指向はオブジェクト指向ではないかもしれない
あなたのオブジェクト指向はオブジェクト指向ではないかもしれない
 
#yidev 第25回勉強会 オープニング
#yidev 第25回勉強会 オープニング#yidev 第25回勉強会 オープニング
#yidev 第25回勉強会 オープニング
 
みんなで Swift 復習会での談笑用スライド – 3rd #minna_de_swift
みんなで Swift 復習会での談笑用スライド – 3rd #minna_de_swiftみんなで Swift 復習会での談笑用スライド – 3rd #minna_de_swift
みんなで Swift 復習会での談笑用スライド – 3rd #minna_de_swift
 
App extension for iOS
App extension for iOSApp extension for iOS
App extension for iOS
 
JVM言語を使ってみようの歌
JVM言語を使ってみようの歌JVM言語を使ってみようの歌
JVM言語を使ってみようの歌
 
Java in the Past, Java in the Future
Java in the Past, Java in the FutureJava in the Past, Java in the Future
Java in the Past, Java in the Future
 

意外と苦労する、一部の画面のみ ランドスケープ表示を許容する方法 (potatotips 第17回)