青柳 @ShinichiAoyagi です。
Microsoftデベロッパーセンターでいろいろしていたらいつの間にかAzure ADが新しくできていて、そのAzure ADを変更することも削除することもできず困ったことになりました。マイクロソフトのサポートに問い合わせて無事解決できましたが自分的には「こんなのわかんねえよ!」だったので記録しておきます。
「Xamarinネイティブによるモバイルアプリ開発 C#によるAndroid/iOS UI 制御の基礎」アップデート情報・正誤表・エラッタ
最終更新日: 2017/12/12
株式会社ディーバ 代表取締役 青柳臣一が執筆した、2017年9月15日発売 Xamarinネイティブによるモバイルアプリ開発 CによるAndroid/iOS UI制御の基礎 (翔泳社)のアップデート情報・正誤表を勝手に記します(適宜この記事を更新します)。
購入者が実際に試した「 テスターが #Xamarin でキッチンタイマーを作ってみた! - Togetter」も参考になります(一部参考にしてここでも記載します)
Chapter 3: Visual Studio で iOS キッチンタイマーを作ろう
リスト 3.24 (p.156) ShowRemainingTime メソッド
誤
private void ShowRemainingTime() { RemainingTimeLabel.Text = string.Format("{0:f0}:{1:d2}", _remainingTime.TotalMinutes, _remainingTime.Seconds); }
正(修正例)
private void ShowRemainingTime() { RemainingTimeLabel.Text = string.Format("{0:f0}:{1:d2}", Math.Floor(_remainingTime.TotalMinutes), _remainingTime.Seconds); }
Chapter 4: Xamarin でアプリを実装する
ポータブル クラス ライブラリ (PCL) p.182
旧 | 新 |
---|---|
ポータブル クラス ライブラリ | クラス ライブラリ(レガシ ポータブル) |
Visual Studio 2017 Ver. 15.3 頃から ポータブル クラス ライブラリ は、レガシ ポータブルと表記されています。
Chapter 5: MVVMCross について学ぼう
誤 | 正 |
---|---|
MVVMCross | MvvmCross |
MVVMCross、MVVM Cross でもなく MvvmCross が公式表記です。ただし、最新のロゴは MVVMCROSS と大文字表記です。
Chapter 8: MVVMCross を使いこなそう
ビューモデルのライフサイクル (p.330, 331)
Start
メソッドは MvvmCross 3.x/4.x 系のライフライクル で使われるメソッドのため非推奨です。
MvvmCross 5.6 の ライフライクル は次のように変更されています。
メソッド名 |
---|
コンストラクタ― |
void Prepare(TParameterModel parameter) |
async Task Initialize() |
void ViewCreated() |
void ViewAppearing() |
void ViewAppeared() |
void ViewDisappearing() |
void ViewDisappeared() |
void ViewDestroy(bool viewFinishing) |
Tips: 注意: Initialize メソッドが呼ばれないケース (p.333)
「今後の MVVMCross では修正されるかもしれませんが」とありますが、Navigation Service を使う場合 Core プロジェクトの App class (App.cs) の下記メソッドを変更します。
誤
RegisterAppStart<ViewModels.MainViewModel>();
正
RegisterNavigationServiceAppStart<ViewModels.MainViewModel>();
12/8 VR技術の現状とこれから@テーマパークEXPO
青柳 @ShinichiAoyagi です。
当日になってしまいましたが、12/6~8に東京ビックサイトで開催されている テーマパークEXPO で「VR技術の現状とこれから」というタイトルのセミナーを担当します。
昨年 に引き続きとなります。昨年のセミナーが好評だったとかで「今年もお願いできませんか?」と運営さんの方から打診がありました。正直、そんなに新しいネタがあるわけではないですがおもしろそうなところをお話しようと思います。技術者向けのEXPOではないので、むしろ技術者視点であれやこれやをお話できればと思っています。
「セミナー/イベント」で「VR」で検索すると出てきます。
- 2017/12/8 12:30-13:30
- A-10【会場A】
現在のディーバの業務内容を紹介。ディーバはソフトウエア開発会社です
青柳 @ShinichiAoyagi です。社長業に力を入れると書いたばかりなのにコーディングが忙しくて他のことがなにもできません。。。ダメだなぁ。
私の 1つ前の記事 で ディーバ の昔話を書きましたが現状について少し書きたいと思います。
ディーバはいわゆるソフトウエア開発会社(システム開発会社)です。パソコンだったりサーバーだったりスマホだったりで動くソフトウエアの開発をしています。
ディーバでは以下のような仕事をしています。
続きを読む社長になって丸7年が経ちました
青柳 @ShinichiAoyagi です。
私が代表取締役を務める 株式会社ディーバ は先月で26期を終え、今月から27期目となります。ほんとに早いものです。
私が代表取締役に就任したのは2010年11月ですから、就任後7期が過ぎ、今月から8期目ということになります。
以下、長文、かつ、単なる昔話、自分語りです。
続きを読むCodeZineにインタビュー記事が掲載されました
青柳です。
書籍「Xamarinネイティブによるモバイルアプリ開発 CによるAndroid/iOS UI制御の基礎」に関連してCodeZineにインタビュー記事が掲載されました。
メールやチャットではなくインタビュワーさんと面と向かって話をしました。時間にしたら30分ちょっとくらいでしょうか?1時間近く話してたかもしれません。話し言葉なのであっちいったりこっちいったりしたと思うのですがすっきりとまとめてくださってます。
(それにしても、自分の写真を見るなんてめっちゃ久しぶりだけどものすごく太いな)
iOS 11 対応でアプリを修正したところ
開発している iOS 10 アプリをそのまま iOS 11.0 で動かすと不具合があったので修正したところです。
※ Xamarin.iOS + MvvmCross およびその他ライブラリを使っている環境です。
Document picker のデザインが異なる
iOS 11 では Document picker の navigation bar が白に、status bar の style が黒文字前提のデザインになっていました。
インポート時 (UIDocumentPickerMode.Import) の UIDocumentPickerViewController を表示したところ。
左: iOS 11 右: iOS 10
iOS 10 アプリでしていたこと
- アプリ全体の navigation bar の背景色・テキストの色を
UINavigationBar.Appearance.BarTintColor
とUINavigationBar.Appearance.TintColor
とで指定 - アプリ全体の status bar の style を info.plist で指定
<key>UIViewControllerBasedStatusBarAppearance</key> <false/> <key>UIStatusBarStyle</key> <string>UIStatusBarStyleLightContent</string>
iOS 11 アプリ用に修正したところ
- iOS 10 で行なっていたアプリ全体の navigation bar の色、status bar の style 指定をやめ、ViewController ごとに毎回指定するようにしました。
NavigationController.NavigationBar.BarTintColor = UIColor.FromRGB(0x3f, 0x51, 0xb5); NavigationController.NavigationBar.TintColor = UIColor.White; NavigationController.NavigationBar.BarStyle = UIBarStyle.Black;
修正後の画面
左: iOS 11 右: iOS 10
Document picker で選んだファイルを開けない
肝心なことが動かなくなっていました。DidPickDocument
イベントが発生せず、iOS 11 からの DidPickDocumentAtUrls
で処理する必要があるようです。
iOS 10 アプリのコード
var picker = new UIDocumentPickerViewController(new[] { "public.item" }, UIDocumentPickerMode.Import); picker.DidPickDocument += (sender, args) => { // Do something }; PresentViewController(picker, true, null);
iOS 11 アプリ用に修正したコード
var picker = new UIDocumentPickerViewController(new[] { "public.item" }, UIDocumentPickerMode.Import); if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0)) { picker.DidPickDocumentAtUrls += (sender, args) => { // Do something }; } else { picker.DidPickDocument += (sender, args) => { // Do something }; } PresentViewController(picker, true, null);
UIActivity で リソースファイルを共有できない
BundleResource としてアプリに組み込んでいるファイルを直接 BundlePath から URL 文字列を作成し UIActivityViewController へ渡すと「〜にコピー」というようなアプリへはファイルを渡せません。
iOS 10 アプリのコード
var path = Path.Combine(NSBundle.MainBundle.BundlePath, "help.pdf"); var url = new NSUrl(path, false); // filepath to url (file://) var activityItems = new NSObject[] { url }; var activityController = new UIActivityViewController(activityItems, null); if (activityController.PopoverPresentationController != null) { activityController.PopoverPresentationController.SourceView = View; activityController.PopoverPresentationController.BarButtonItem = _shareButton; } PresentViewController(activityController, true, null);
iOS 11 アプリように修正したコード
対象のファイルを一時フォルダーにコピーするようにしました。
var path = Path.Combine(NSBundle.MainBundle.BundlePath, "help.pdf"); var tempPath = Path.Combine(Path.GetTempPath(), "help.pdf"); File.Copy(path, tempPath, true); var url = new NSUrl(tempPath, false); // filepath to url (file://) var activityItems = new NSObject[] { url }; var activityController = new UIActivityViewController(activityItems, null); if (activityController.PopoverPresentationController != null) { activityController.PopoverPresentationController.SourceView = View; activityController.PopoverPresentationController.BarButtonItem = _shareButton; } PresentViewController(activityController, true, null);
UIToolbar 上の UIButton が押せない
トリッキーなコードですが、UIToobar の Subview に追加した UIButton がタップできません。
このコードがあるのが BTProgressHUD 。loading/progress 画面のキャンセルボタンが反応しません。ACR User Dialogs で参照しているライブラリなので ACR User Dialogs を使っていても問題が起こります。
※ iOS 10 では動いているので view の UserInteractionEnabled を true する話とは違います。
調べていると UIToolbar にひとつ以上 UIBarButtonItem があると UIButton も押せるという回避策を見つけました。
iOS 11 アプリでは、とりあえずライブラリのコードを修正して UIToolbar を使わず UIView に置き換えました。
MvvmCross で UITableViewCell の要素の binding で表示不具合
ニッチなのでさらっと紹介すると、MvvmCross を使って ViewModel 側でリスト項目のテキストやアイコン画像を cell の view(ImageVIew など)に binding していました。
iOS 11 では UITableView の表示と ViewModel に値を設定するタイミングで、ImageView.Image への binding している画像が表示されない現象が起きました。
View 側:
public class CustomStyleCell : MvxTableViewCell { [Export("initWithStyle:reuseIdentifier:")] public CustomStyleCell(UITableViewCellStyle style, NSString cellIdentifier) : base("", UITableViewCellStyle.Value1, cellIdentifier) { var set = this.CreateBindingSet<CustomStyleCell, ListItemViewModel>(); set.Bind(TextLabel).To(vm => vm.Text); set.Bind(DetailTextLabel).To(vm => vm.DetailText); set.Bind(ImageView).For(v => v.Image).To(vm => vm.Image).WithConversion(new NameToUIImageValueConverter()); set.Apply(); } }
public class NameToUIImageValueConverter : MvxValueConverter<string, UIImage> { protected override UIImage Convert(string value, Type targetType, object parameter, CultureInfo culture) { return (value == null) ? null : UIImage.FromBundle(value); } }
ViewModel:
public class ListItemViewModel : MvxNotifyPropertyChanged { public string Text { get => _text; set => SetProperty(ref _text, value); } private string _text; public string DetailText { get => _detailText; set => SetProperty(ref _detailText, value); } private string _detailText; public string Image { get => _image; set => SetProperty(ref _image, value); } private string _image; }
iOS 11 アプリ用に修正したコード
iOS 11 アプリでは MvxTableViewSource の GetOrCreateCellFor
内で生成した cell の ImageView.Image へ直接 ViewModel の値を設定するように「も」しました。
public class CustomTableViewSource<TCell> : MvxTableViewSource where TCell : MvxTableViewCell { protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item) { var cell = tableView.DequeueReusableCell("cellIdentifier"); var vm = (ListItemViewModel)item; if (vm != null) { // workaround if (!string.IsNullOrWhiteSpace(vm.Image)) cell.ImageView.Image = UIImage.FromBundle(vm.Image); } return cell; } }