2020年5月31日日曜日

iPhoneアプリのiPad対応3 - Drag and Drop

iPad対応 第3回目は、Drag and Drop。
SplitViewで、複数のアプリを同時に表示するメリットの一つが、他アプリのデータをDrag and Dropでコピーできること。

UITextField, UITextAreaは、デフォルトでテキストのDnDに対応している様子。
今回対応中のレシピアプリでは、画像が登録できる機能があるので、他アプリから画像をDropで追加できるようにしてみた。



Web上の画像をアプリに登録する場合は、かなり楽になる!
Drag and Dropの仕組みは、iOS 11以上のUITableView, UICollectionView で実装が可能。

Dropの実装

使用するのは、UITableViewDropDelegate

canHandleのメソッドで、受け取り可能なClassかをチェックする。今回はUIImageのみ可能に。

Dropの処理は、以下のように実装した。
UITableViewDropPlaceholder で一時的なViewを作り、処理が完了したら削除する。

Dragの実装

Dragを実装すると、外部アプリへデータをドラッグできるようになる。使用するのはUITableViewDragDelegate
itemsForBeginning で、受け渡したい情報を設定する。

DragDelegateとともに、tableView(_:canMoveRowAt:)tableView(_:moveRowAt:to:) などを実装すると、テーブル内のセルの順番をDnDで操作することも可能になる。
以下は、同じSection内に限りDnDで行を入れ替えることができる実装例。


外部アプリにデータを渡さないのであれば、itemsForBeginningの戻り値は設定なしでOK。

ただし、tableView(_:moveRowAt:to:) の処理中で、tableView.reloadSections で更新すると、次回から行移動ができなくなるバグ?があるみたいなので注意。tableView.reloadData() だと大丈夫のようだ。

iPadだと、登録がかなり楽になる! 素敵!
次回につづく。
• • •

2020年5月30日土曜日

iPhoneアプリのiPad対応2 - Readable Width

読みやすい表示幅 - Readable Width

iPhoneアプリのiPad対応。前回のSplitViewに続いて、今回は表示幅について。


画面の横幅が大きくなったとき、デフォルトのMarginサイズだと横に間延びして読みにくくなってしまう。
読みやすい表示幅を制御する仕組みはすでにOSにあり、Readable Width を設定すれば反映できる。
(iOS 12以上で利用可)

設定方法

Storyboard > Size Inspector の "Follow Readable Width" がその設定になる。

ちなみに、Preserve Superview Marginsは、SuperviewのMarginも考慮するプロパティ。カスタムテーブルセルを作るとき、標準セルのMarginと合わせることができます。

Readable Widthの幅は、OSで設定されているText Sizeによって変わるのに注意。
Text Sizeが大きくなると、幅は大きくなる。

デフォルトのMarginを無しでReadable Widthのみ反映する

レシピの画像は、Compactサイズでは左右Margin無し、Readable Widthが反応するサイズではそのMarginに反応するよう設定した。
この設定は以下の通り。

Layout Margins は 0 を設定し、Follow Readable Width にチェックをいれる。
これで、以下のように、画面幅に応じてMarginが切り替わる。


Readable Marginのサイズを取得する

UIViewのlayoutMarginsに、Readable Widthも含めたMarginが含まれている模様。
ただ、アプリ操作途中でOSのText Sizeを変えることによりReadable Widthの幅が変わった場合、layoutMargins には変更後の値は含まれていないっぽい。(iPadOS 13.5 で確認)


iPhoneアプリをiPad対応する際、Readable Marginの対応することは多くありそう。
Storyboardの設定だけで完結できるのはとても良い。

次回につづく。
• • •

iPhoneアプリのiPad対応1 - SplitView

iPadOSMac Catalyst のお勉強として、既存のiPhoneアプリ Recipe Note のiPad対応を試し中。WWDC 2020 でなにか進展がありそう予測も兼ねた復習として。
学んだこと、迷ったことを書いてみる。

OSになるべく逆らわず、以下の基本方針で。

  • iPhone/iPad で同じUI(Storyboard)を使う
  • UIDevice.currentDevice().userInterfaceIdiom でOSの条件分岐しない
  • Size Classでの条件分岐しない

UISplitViewController

iPadOSでSplit Viewの操作をすると、大きいサイズ(Regular) ⇔ 小さいサイズ(Small) が頻繁に切り替わることになる。
その操作をしても、いい感じの表示にするには、やはりUISplitViewController を使いたい。



UISplitViewController を使うポイント

状態の設定と取得

SplitViewの種類は、preferredDisplayMode で設定できる。
Master/Detailを両方表示(例: 設定アプリ)や、MasterをOverlay表示など。
isCollapsed で折りたたまれているかどうか?を取得できる。

displayModeButtonItem を、navigationItem.leftBarButtonItem に設定することにより、Back / 全画面表示 の処理をするボタンが表示できる。上記動画の右ペインの左上にあるボタンがそれ。状態によって表示も自動的に切り替わってくれる。

サイズに関する挙動差

Master(左ペイン) → Detail(右ペイン)と画面遷移していく、それらの画面がどこにStackされるのかは、Splitの表示状態によって異なる。
サイズがSmall、つまり1ペイン表示のときは、MasterのUINavigationViewControllerにStackされ、サイズがRegularのときは、UISplitViewControllerにStackされる。

iPhoneのときは初期表示をMasterのみにする

UISplitViewControllerのDetailにViewがあると、デフォルトでは初期表示はDetailになる。
iPhoneのときは初期表示をMasterのみにしたい場合は、UISplitViewControllerDelegate の splitViewController(_:collapseSecondary:onto:) で制御する。

Masterのみにしたい場合、false を返せばOK。
このメソッドは、iPhoneの初期表示だけでなく、サイズがRegular → Smallに変わった場合にも対応する。

ちなみにMasterのViewControllerにSplitViewのDelegateを設定したい場合、delegateの設定をviewLoadでしても間に合わないので、awakeFromNibで行う。(が、SplitView継承してカスタマイズする方がよいかもしれない)

Small → Regularに変わったときのDetailの指定


上記のコードでは、MasterのUINavigationViewControllerがTopのときは「なにも設定されていないView」をDetailに設定、それ以外はデフォルト = 表示されていたViewがDetailに表示 するようにしてみている。


当初は、「なにも設定されていないView」を使わない方法でアレコレ試していたが、いろんなパターンに対応するのは大変なので、使用する形の方が素直に実装できると思った。

Tabをデフォルトの挙動に合わせる

今回、Tabの中にSplitViewを入れる形で実装を進めているのだが、そうすると動かくなった機能がある。
  1. Hide Button Bar on Push (タブを非表示にする設定)
  2. TabItemタップ時、NavigationのTopに戻る
1については、setNavigationBarHiddenを使って自前で制御するしかない予感。iPhoneのときのみタブを非表示にしようかとも思ったが、無理に制御しないほうが無難かもと思い中。

2については、UITabBarControllerDelegate で以下のコードをいれてみた。

折りたたまれているときは、NavigationをRootに遷移。折りたたまれていない + Masterが非表示の場合には、Masterを表示する。(preferredDisplayModeにはallVisibleを設定している)

ちなみに、SplitViewのドキュメント
Split view controllers are normally installed at the root of your app’s window.
とあるので、Window Root以外にSplit Viewを使うのは推奨されていないかもしれない。


今回はここまで。
次回はSplitView以外のことを書いていこうと思う。
• • •