2015年5月30日土曜日

layoutSubviews で座標変更した UIView がスクロールすると元の座標に戻る

タイトルの通りになりますが、ScrollView 上に配置した UIView(ボタンとかラベルとか)を、layoutSubviews 内で座標を変更後、表示をすると座標が変更されて正常にみえますが、スクロールをすると、変更前の座標に戻ってしまいます。

この現象は、AutoLayout を使用している場合に発生します。
ViewController 毎に AutoLayout の設定を解除できるようなプロパティを設定したのですが意味がなかった(!?)。

ここで、AutoLayout と書いていますが、これに気づくまでに相当悩みました。

処理の流れをみると、座標の変更を行う layoutSubviews は、表示の時の 1 度だけ通過して、スクロールの時には処理を通らない。。。
安易な回避策として、同じ UIView を 2 つ用意し、座標前と変更後用の UIView の hidden を切り替えようかと考えましたが、内部の処理が冗長になるのでできれば同じものを使いまわしたいと思っていました。

UIScrollview, move, position... などと少ないボキャブラリーの中からキーワードを試行錯誤して検索しました見つかりませんでした。

今一度、起こっている現象と状況を辿って行くことにしました。

通常、AutoLayout を使用する場合、座標の変更を行わないのであれば制約を付けないか、位置とサイズの制約を使用するようにします。
と言うことは、座標をずらす場合には、layoutSubviews で、ずらした部分の制約をつけていく必要があるのでは?と思ったわけです。

つまり、スクロールした時点で AutoLayout が動き制約を実施する行うが、座標変更後の制約の設定がないため元の座標のまま放置されると言った動きになっているのではないかと。

どうやら、これが当たりのようでした。
たぶん、storyboard で画面レイアウト等をされない方は、すぐに現象の理解ができたのかもしれません。。。

同じ現象で悩んでいる人(が居るのか?)の為に、今回とった方法を記載します。

1. storyboard で、変更前の座標に配置し制約を付ける。


2. 制約をアウトレットで接続する。


3. layoutSubViews で、条件を判定して制約を付け直す。
- (void)layoutSubviews
{
    [super layoutSubviews];
    
    self._button.translatesAutoresizingMaskIntoConstraints = NO;

    // 制約を解除
    [self._scrollView removeConstraints:@[self.widthConstraint]];

    // 条件によって X 座標を変更する制約を付ける
    if (self.isFlag) {
        self.widthConstraint
        = [NSLayoutConstraint constraintWithItem:self._button
                                       attribute:NSLayoutAttributeLeft
                                       relatedBy:NSLayoutRelationEqual
                                          toItem:self._scrollView
                                       attribute:NSLayoutAttributeLeft
                                      multiplier:1
                                        constant:20];
        
    } else {
        self.widthConstraint
        = [NSLayoutConstraint constraintWithItem:self._button
                                       attribute:NSLayoutAttributeLeft
                                       relatedBy:NSLayoutRelationEqual
                                          toItem:self._scrollView
                                       attribute:NSLayoutAttributeLeft
                                      multiplier:1
                                        constant:120];
        
    }
    // 制約を再付与
    [self._scrollView addConstraints:@[self.widthConstraint]];
}
 
ポイントは、制約を接続してコード上で操作できるようにしてから、制約を付け直すという部分になります。
手順で書くとあっという間なのに相当な労力が、、、こんな現象で困っている人がいるのかわかりませんが参考になれば。

2015年5月28日木曜日

続、Facebook SDK for iOS 4.0 に悩まされる

先日、表題の記事を書いた所、コメントを頂きましたのでそちらの確認をさせて頂くのと、Graph API を使用する方法を試してみましたので報告を。。。

まず、コメントで頂いた方法を試させていただきました。
(kota n さん。ありがとうございます。)
さっそく必殺のコピペをして動作を見てみるとログに以下のメッセージが。。。
FBSDKLog: Warning: [FBSDKAccessToken currentAccessToken] is missing publish_actions permissions
どうやら publish_actions という権限が必要なようです。
この権現の扱いというのがややこしく、理解するのに暫く時間がかかりました。

しかも、この publish_actions の権限は、Facebook に審査を通していないと、使用時に警告文が表示されるようです。
(あくまで、警告文なので製品アプリだとまずいですが、お試しなので強行突破すれば確認を取ることは出来ます。 テストユーザ(警告が出ない?)ってものあるようですが調査不足。)

この権限の付与は、Graph API を使用する際にも設定の必要がありますので、ひとまず Graph API を使用した方法を載せます。

権限を付与するためには、まずログインの動作が必要となります。
ログインは以下コードでログイン動作を行います。
    - (void)login
    {
        if ([FBSDKAccessToken currentAccessToken]) {
            // accessToken が取れるならログイン処理は完了している
            reutrn;
        }

        FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
        [login logInWithReadPermissions:@[@"email"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
            if (error) {
                // Process error
                NSLog(@"Error");
            } else if (result.isCancelled) {
                // Handle cancellations
                NSLog(@"Cancel");
            } else {
                // If you ask for multiple permissions at once, you
                // should check if specific permissions missing
                if ([result.grantedPermissions containsObject:@"email"]) {
                    // Do work
                    NSLog(@"Login OK");
                }
            }
        }];

    }
このコードを走らせると、Safari が起動してログイン画面が起動し、その後アプリのアクセス許可を聞いています。
OK または、キャンセルを押すと、アプリに戻ります。

OK を押した場合はログインと、アプリの使用許可が出来た形となります。
次に、publish_actions の権限を付与するコードを使用します。
ログインが出来た状態だと、権限の付与ができるようになっています。
    - (void)addPermission
    {
        if ([FBSDKAccessToken currentAccessToken]) {
            // publish_actions の権限確認・付与
            if ([[FBSDKAccessToken currentAccessToken] hasGranted:@"publish_actions"]) {
                // TODO: publish content.
            } else {
                FBSDKLoginManager *loginManager = [[FBSDKLoginManager alloc] init];
                [loginManager logInWithPublishPermissions:@[@"publish_actions"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
                    //TODO: process error or result.
                }];
            }
        }
    }
またここでも、権限の付与確認のために Safari が起動します。
ここで、審査を通していないと、赤文字で警告文が表示される様になっています。
日和らずテストなので OK しましょう。

ここまで来ると、あとはメッセージを投げるだけ!以下の内容の処理を使用します。
    - (void)sendMessage:(NSString *)message
    {
        if ([[FBSDKAccessToken currentAccessToken] hasGranted:@"publish_actions"]) {
            [[[FBSDKGraphRequest alloc]
              initWithGraphPath:@"me/feed"
              parameters: @{ @"message" : @"hello world"}
              HTTPMethod:@"POST"]
             startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
                 if (!error) {
                     NSLog(@"Post id:%@", result[@"id"]);
                 }
             }];
        }
    }
これで、完了と。。。
非常に端折って書いているので、正確性は怪しいですが投稿はできるはず。。。

コメントで頂いた内容についても、public_actions の権限を設定したあとからだと、うまくメッセージが送ることを確認しました。
ただ、同じメッセージが2回投稿される現象がでている(!?)ので調査が必要な状態。

気になる点は、権限を外したりログアウトはどうやるのかですが調べた所、権限の削除については、コードから可能。
ログアウトの処理は、Safari で Facebook を開くとログイン状態になっているので、そこからログアウトすれば良いみたい(これもコードで出来るのか?)。
登録したアプリ自体も Facebook の自分のページの設定の項目から削除することができます。

なんか投稿までの流れはコードでできたけど、解除や削除は手動になるっていうのが、今ひとつな感じです。
ともあれ、Graph API を使用しての投稿ができたので、ここから掘り下げていけば良いかなと思う次第です。

駆け足で書いたので、間違っているかもしれません。
しかし、なぜメッセージ等の投稿が Graph なんだろうか?

2015年5月17日日曜日

Facebook SDK for iOS 4.0 に悩まされる

今回は、Facebook SDK for iOS を使用して、タイムラインにメッセージを投稿する方法を調べてみました。

使う方法を書く前に、苛立ちを少々書かせてください。

まず、バージョンがややこしい。
Developers のページをみると、現在?の SDK のバージョンが v3.18 と書かれています。しかし、更新履歴のページに行くと、v3.23.2 となっています。
さらに、もう一つ Changelog があり、そちらを見ると、v4.0.1 がでてきます。
また、github にもリポジトリがあり、こちらは 4.0.1 が最新となっています。

Developers の Facebook SDK for iOS ページ
https://developers.facebook.com/docs/ios?locale=ja_JP

Developers の Facebook SDK for iOS の更新履歴のページ
https://developers.facebook.com/docs/ios/change-log-3.x/

Developers の Facebook SDK for iOS のもう一つの更新履歴のページ
https://developers.facebook.com/docs/ios/change-log-4.x

github の Facebook SDK for iOS ページ
https://github.com/facebook/facebook-ios-sdk

次に、バージョン 3 系と、4 系ではメソッドが変わっている。。。
Web で使い方の参考を拝見させて頂くにしても、みなさん 3 系の方法で書いているために、最新の 4 系では、過去の資産が活かせないということになる。
そして、4 系のサンプルはあまりない。

まあ、要するにハッキリ言うと Facebook SDK って、クソ難し過ぎませんか!!ってことです。

と、毒ついたところで、タイムラインへの投稿までの手順を書いておきます。

断りとしては、この方法では一旦 Safari が起動してログイン認証した後、メッセージを送るときも Safari が起動してメッセージを投稿するという、 UI としていかがなものか?という内容になることをご了承願います。

1. Facebook SDK for iOS を導入する

まずは、Facebook SDK を入手します。
入手場所は、Developer のページまたは、github からの入手でも構いませんが、CocoaPods を使用するのが簡単だと思います。

まずは、Xcode で確認用のプロジェクトを作成。
つぎに、プロジェクトのフォルダに Podfile を作成して、以下を記述。

    pod 'Facebook-iOS-SDK'

ターミナルで、Podfile の場所まで移動して、pod install で導入を行います。
導入のバージョンを指定していないので最新の 4.0.1 が導入されます。

次に、Developer のページで動作するアプリを登録します。
アプリを登録することによって、アプリの ID を取得することが出来ます。
このアプリの ID は、iPhone アプリでの設定に必要です。

次に、Xcode で Supporting Files フォルダにある xxx.plist に必要項目を追加します。
- FacebookAppID : Facebook アプリのID
- FacebookDisplayName : Facebook アプリ名
- URL types > item 0 > URLSchemes > item0 : fb + Facebook アプリID


2. 投稿用のボタンを作成してコードを割り付ける

ここまで来ると、もう 8 割がた終わっています。
Developer のチュートリアルのページだと、導入後は AppDelegate.m へのメソッドの追記などが書かれていますが、メッセージをポストするだけだと特に記述がいらない?みたいです。
細かな制御を行う場合には、記述が必要になるので、必要になったら追って確認するようにします。

さて、実際の方法ですが、まずは、storyboard にボタンを配置して、action を追加します。そして、追加したアクションに以下の記述をします。
FBSDKShareDialog の withContent に何か値を渡さないと実行時エラーになるので FBSDKShareLinkConten のインスタンスを渡しています。正直この方法もいかがなものか?と思っています。

        FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc] init];
        [FBSDKShareDialog showFromViewController:self
                                     withContent:content
                                        delegate:nil];    

3. 動作の確認

後は、動作の確認です。
シミュレータでもよいので、起動してボタンを押すと Safari が起動して Facebook のログイン画面が起動します。
ログインが成功すると、次にメッセージを入力する画面が起動します。
ここで、文字を入力して Share ボタンを押すと、自分のタイムラインに投稿が行われています。
そして、アプリの画面に自動的に戻ります。


4. 一応のログアウト

ログアウトは、今回の場合ではアプリ側でログアウトを行う方法はなく、アプリ終了や、Home ボタンを押してバックグラウンドに回した後に、 Safari を起動して Facebook へアクセスし、ログアウトを行う手順をとります。


ね、イケてないでしょ

すみません。
ハッキリ言ってこの方法では、メッセージを送るたびに Safari が起動して投稿したとアプリに戻るという、いったりきたりの面倒くさいアプリとなってしまいます。いちいち切り替えを行わなくて良い方法を探してみたいと思いますが、なんせわかりにくい。。。

たかが、ログインして、メッセージを投稿して、たまにログアウトしたいだけなのに、独自の方法を使おうとすると、なんでこうも難しいのか。

それとも、自分がポイントを押さえていないだけなのだろうか?
追記:
Graph API ってのを使えば行けるのか(?)、あとで調べてみる。

Written with StackEdit.

2015年5月11日月曜日

WPF で横長(Landscape)印刷をする

久しぶりに WPF の内容。
正直、こういった技術系の内容は時間が無いと書けない。

何故か?動くコードを載せたいけど、実業務で動いているコードは載せれないし、それを加工するにも結構時間がかかるから。

だから、技術系の blog 書いている人とか、専門サイトに記事を投稿している人はすごいと思う。
あと、ブログとは関係ないけど、動画を上げている人も同様。

いずれも内容がさらっと読めたり、動画見ている時間があっと言う間に過ぎていく様に仕上げるには相当な時間と経験が必要。
やったことない人にしてみたら、大した作業(内容)でないと思うかもしれないが、実際にやってみると結構大変かつ時間がかかる作業というのがわかると思う。きっといい経験ができるだろう。

前置きが少し長くなったが、今回は WPF で横長の印刷を行う部分で困っていたが、なんとか印刷できるようになったので、雰囲気程度にコードを載せようと思います。
実コードから居る部分だけ残したので、動かないコードだとは思います(さっきと言っている内容が違うのは気にしない)。

    PrintDialog printDialog = new PrintDialog();
    if (printDialog.ShowDialog() == true) {
 
        System.Windows.Documents.FixedDocument fixedDoc = new System.Windows.Documents.FixedDocument();
 
        HogePaper paper = new HogePaper();
        var PageSize = new Size(paper.Height, paper.Width);
        paper.Content = null;
 
        System.Windows.Documents.FixedPage fixedPage = new System.Windows.Documents.FixedPage();
        fixedPage.DataContext = this;
        fixedPage.Children.Add(paper.PrintArea);
 
        fixedPage.Measure(PageSize);
        // Point 1!! XAML の画面幅を指定する。
        fixedPage.Arrange(new Rect(15, 15, PageSize.Height, PageSize.Width));
 
        fixedPage.UpdateLayout();

        // Point 2!! 印字出力範囲を指定する
        fixedPage.Width = 11.69 * 96;
        fixedPage.Height = 8.27 * 96;

        System.Windows.Documents.PageContent pageContent = new System.Windows.Documents.PageContent();
        ((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
        fixedDoc.Pages.Add(pageContent);
 
        paper.Close();
 
        try {
            // Point 3!! XPS 以外の印刷時に横長にする。
            printDialog.PrintTicket.PageOrientation = System.Printing.PageOrientation.Landscape;
            printDialog.PrintDocument(fixedDoc.DocumentPaginator, "print a hoge");
        } catch (ArgumentException) {
            return;
        }
    }

XAML 側については、Width(29.7cm) と、Height(21cm) の指定をしてしておく必要があります。

Point1, 2 については、印刷の範囲を指定する部分となります。
ここを指定しないと、用紙は横長なのにデータは縦長で印字される状態になります。

Point 3 については、直接プリンタ出力だったり、PDF に出力すると、これまた用紙が横なのに縦印刷になるという状態になるのを防ぐための指定。
ふざけているのかと思うのが、XPS への出力場合はこの指定がなくても良いということ。あっても問題ないので付けておくほうがよいでしょう。

しかし印刷するだけなのにここまで、面倒なのか。。。
最初は組み合わせや、プロパティの指定などが分からず、いくらやっても縦長で表示しかされないので、きっと横長印刷はできないんだと思い込んだぐらい。

調べるにしてもキーワードが分からず、魂が抜けかけたが、stackoverflow に助けられた。
http://stackoverflow.com/questions/2493244/wpf-to-xps-in-landscape-orientation
http://stackoverflow.com/questions/26624838/print-a-usercontrol-to-the-center-of-an-a4-page

本当にありがたい。
この記事が同じように悩んでいる人の助けになればいいがと思って締めたいと思います。

Written with StackEdit.

2015年5月9日土曜日

Pebble Watch の有効利用

Pebble Watch を購入して、大体 3 ヶ月弱が経とうとしています。

この記事を書く間に Apple Watch も発売され、スマートウォッチを目にする機会が多くなるかと思いきや、いまだ Apple Watch どころか、スマートウォッチと呼ばれる物を着けている人に会っていません(会社以外の人に会っていないのは否めませんが)。

また、Yahoo などにスマートウォッチのニュース記事が出ようものならコメント欄には「いらねぇ」「流行る気がしない」などのコメントばかり(批判的なコメントを打つ自体で、注目されているとも取れますが、このコメントにより購入意欲が削がれるのもあるかと思うのでなんとも)。
実際、他の人に見せても反応は今ひとつ。

まあ、仕事上この手の物に触れておかないとと言うのと、昔からこういったガジェット系に興味を持っているので、好意的に受け入れるのだと思います。

で、実際の所どうよ?という事を書くのと、おすすめのアプリがあるので、紹介します。

使用感とおすすめアプリ
使用感については、特に違和感を感じず使えています。
電子インクを使用していると言うこともあり、常に文字盤は確認出来ますし、時計自体が熱くなることもありません。
通知が手元で見えるのは、やはり便利で、以前に合った電話の着信が気づかない点が解消されたのはとても良いです。

本来 Pebble は、英語ベースのため、通知の時など、日本語の表示をしようとすると、文字化けを起こしていたのですが、日本語対応パックを作成された方がおり、それを導入することにより、不自由なく使用することができるようになりました(日本語対応パックは、ドネーション形式のソフトです)。

Pebble 日本語言語パック
http://wh.to/pebble/index_jp.html

この通知だけでも便利なのですが、身につけている間のアクティビティを取れるようにすれば、もっと便利に楽しくなります。
(ただ、電池は消費するので、この点は楽しさと引き換えということでしょう。)

そのなかでも、おすすめするのが、「Steps」というアプリと、「Misfit」というアプリ。

Steps については、読んで字のごとく言わる万歩計ですが、歩数のカウントがリアルに刻まれて行って、見ていてとても楽しいアプリです。見ていて楽しいというのは結構重要な要素だと思っています。
欠点は、バックグラウンドでの動作が出来ない点と、記録がその場限りとなってしまう点です。

次に、Misfit。
こちらも、Steps と同じく万歩計を兼ねたアプリ。
すでにアクティビティを取得するデバイスが販売されており、そのメーカーが Pebble 用にアプリを作った形となっています。

Misfit
http://misfit.com/

ただ、データはリアルタイムには更新されないので、見ていても面白みが欠けます。
また、iPhone のヘルスケアとも連動します(正直ヘルスケアの存在意義がわからない)。

Misfit の画面

なぜアクティビティを取るアプリを 2 つ使うかと言うと、Misfit のアプリは、バックグラウンドでの動作が可能。そして、スマートフォンとの連携も取れます。
要するに、見た目の面白さのアプリと、データの取得を行うためのアプリを合わせ技で使う様にしたわけです。

これで、使っていますが、運動ができる時には動こうかと思う様になりました。
あ、あと Ingress も始めたので歩数とポータルの関係を見て調整できる点も続けれる秘訣なのかもしれません。

Steps Misfit

充電について
次に、スマートフォンの問題点というべき充電について。

Pebble(自分のは steel と言うバージョン) については、公式では 5 日程度連続動作可能となっています。

電池の具合をパーセント形式で確認できる watch face を使用してみると、上記の様なバックグラウンドで動くなどの特殊なアプリを入れていないと大体、公式通りの日数は電池が持つ形となります。

自分は、普段 PC の前にいるので、その時は外していて、その間に充電するようにしています。よって、充電の面倒さは感じていない状態です。

総括
自分としては、時間も分かり、アクティビティも取れるのであれば、十分便利な物と思っています。
どうしても小さな画面なので、過度な期待は持っていなかったという点も良かったのかと思います。

これは、持論ですが、スマートウォッチは今のところ、 PC やスマートフォンの補助的な装置で、PC 等の母艦となる機器がスマートウォッチの機能を凌駕しているので、そういった機器の前では外していても何ら問題ないかと思っています。

逆に日中 PC 等の機器の前にいない仕事をしている人には今のスマートウォッチは電池の関係で向かないと思います(便利さよりも稼働できる時間の方が重要と思うため)。

実際の所、スマートウォッチの便利さは、使って見ないと分からないと思います。Pebble や Apple Watch、Android 系スマートウォッチの様なアプリをインストールするタイプ以外にも、通知だけを受け取れる組み込みタイプの物があり、このタイプだと、クォーツ時計の組み合わせで電池の持ちも良いので、まずはこちらで通知の便利さだけでも試して見るのも良いかもしれません。

Written with StackEdit.

2015年5月5日火曜日

青軸キーボードを購入した

家では、これまで Apple のワイヤレスキーボードを使用していました。

見た目は非常におしゃれで、インターネットや簡単なメールには、不自由ないキーボードでした。

しかし、長文を入力したり、プログラミングなどをしているとちょっとしんどさが出てきていました。
どうしても平べったので、押した感じが少なく感じ、叩きつけるようにしてしまっていたのです。
そこで、今回新たにキーボードを新調することにしました。

家の机のスペースの関係上、省スペースキーボードの物を探す必要がありました。

省スペースにも、矢印キーが Fn キーを使うものと、テンキーレスの物があります。
IDE のショートカット(デバック時のステップ実行など)を考えると、Fn キーを押さなくてもファンクションキーや方向キーが独立したものを探す必要がありました。

また、キーボードを選択するにあたって、必要な項目として、キーボードのスイッチの部分ですが、

  • 静電容量無接点方式
  • メンブレン方式
  • 機械式

と、3 種類が存在します。
会社では、静電容量の物を使用しているので、家でも同様にと思いましたが、少々高価なのと、家に帰ってまで会社の感覚を味わわなくても良いだろうと言うことで、ひとまず候補から外しました。
(一応の候補としては、東プレの Realforce87UB か面白そうなところで、 LEOPOLO FC660C ← 方向キーは独立しているが、ファンクションは Fn キーを使用しないといけない。しかし、面白そう。)

メンブレンに関しても、リベルタッチ(富士通)という物が存在するが、テンキーレスがないので、候補から外しました。

そして機械式、省スペース物なら簡単に探すことが出来たので、今回は機械式から探すことにしました。

しかし、まだ終わらない。
今度は、スイッチにも種類があり Cherry MX スイッチを採用した物や、IBM 系のバックスプリング方式のものや ALPS スイッチを使用したものがあります。

とはいえ、Cherry MX スイッチ以外は、更にマニア層向けらしく、種類としては限られ修理もできるか出来ないか分からない感じのものとなるので、無難な物から選択することにしました。

と、なると後は簡単かと思いきや、Cherry のスイッチにも種類があります(黒軸、茶軸、青軸、赤軸の 4 種類)。
それぞれのレビューなどを見ると、大体茶軸か青軸がよく書かれており、黒と赤は、やや少ない。

こればっかりは現物を見ないと分からないのですが、なにせ地方なので現物を置いてある所が無かったりします。
例えあったとしても、この手のものは、長時間使用しないとわからないだろうから、ここは先人の知恵を借りることとにしました。

かなり前置きが長かったのですが、結局購入したのは、打鍵音が大きいという青軸にしました。

機械式のキーボードの販売だと、FILCO と言うメーカーが結構有名なので、FILCO から探していたのですが、他にもアーキサイトというメーカーにも省スペースの物があり、しかも FILCO よりもお買い得だったので、今回はアーキサイト製の物を購入しました。

で、現物がこちら

物が到着したので早速使用して、このブログを書いていますが、聞きしに勝る音の五月蝿さ。
心地よい音と言うには、ちょっと音が大きすぎるかもしれません。
キーの入力具合も今のところ不満はないので、暫くはこのキーボードを使用して見たいと思います。

Written with StackEdit.