SIN@SAPPOROWORKSの覚書

C#を中心に、夜な夜な試行錯誤したコードの記録です。

Xamarin.Forms 特定のキーワードを含むツイートを検索

【 Xamarin 記事一覧 】


@ytabuchiさんのTweetに反応して・・・
f:id:furuya02:20150120031652p:plain

@ch3coohさんのBlogで紹介されていた、CoreTweetをXamarin.Formsに載せてみました。


C#とCoreTweetを使って特定のキーワードを含むツイートを検索する - 酢ろぐ!


CoreTweetのインストール

パッケージマネージャコンソールで一発でした。
※PCLだけでOKです。

PM> Install-Package CoreTweet
依存関係 'Newtonsoft.Json (≥ 4.5.11)' の解決を試みています。
'Newtonsoft.Json 4.5.11' をインストールしています。
'Newtonsoft.Json 4.5.11' が正常にインストールされました。
'CoreTweet 0.4.0' をインストールしています。
'CoreTweet 0.4.0' が正常にインストールされました。
'Newtonsoft.Json 4.5.11' を SearchTweet に追加しています。
'Newtonsoft.Json 4.5.11' が SearchTweet に正常に追加されました。
'CoreTweet 0.4.0' を SearchTweet に追加しています。
'CoreTweet 0.4.0' が SearchTweet に正常に追加されました。

セルのビュー

↓のコードを殆どそのまま使用しました。

Xamarin.Forms ListViewでTwitter風のレイアウトを作成してみました(機種依存コードなし) - SIN@SAPPOROWORKSの覚書


できた!?

一応できたんだけど・・・何故かAndroidだけ画面が遠慮がちになっている。

Android iOS WindowsPhone
f:id:furuya02:20150120033039p:plain:w150:left f:id:furuya02:20150120032745p:plain:w150:left f:id:furuya02:20150120032848p:plain:w150:left

書いたコードは、下記で全部です。PCLのみになってます。

namespace SearchTweet {
    public class App : Application {
        public App() {
            MainPage = new MyPage();
        }

        protected override void OnStart() {
            // Handle when your app starts
        }

        protected override void OnSleep() {
            // Handle when your app sleeps
        }

        protected override void OnResume() {
            // Handle when your app resumes
        }
    }

    //1つのTweetを表現するクラス
    internal class Tweet {
        public string Name { get; set; } //表示名
        public string Text { get; set; } //メッセージ
        public string ScreenName { get; set; } //アカウント名
        public string CreatedAt { get; set; } //作成日時
        public string Icon { get; set; } //アイコン
    }


    internal class MyPage : ContentPage {

        //データソース(class Tweetのコレクション)
        private readonly ObservableCollection<Tweet> _tweets = new ObservableCollection<Tweet>();


        public MyPage() {

            var entry = new Entry {
                HorizontalOptions = LayoutOptions.FillAndExpand,
                Text = "愛宕"
            };

            var button = new Button() {
                Text = "Search"
            };
            button.Clicked += (sender, args) => {
                Refresh(entry.Text);
            };

            var layoutTop = new StackLayout {
                BackgroundColor = Color.FromRgb(169, 206, 152),
                Padding = 5,
                Spacing = 10,
                Orientation = StackOrientation.Horizontal,
                Children = {entry, button}
            };

            //ListViewの生成
            var listView = new ListView {
                ItemTemplate = new DataTemplate(typeof (MyCell)), //セルの指定
                ItemsSource = _tweets, //データソースの指定
                HasUnevenRows = true, //行の高さを可変とする
            };

            var layout = new StackLayout {
                Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0), //iOSのみ上余白
                //2015.01.21修正
                //VerticalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Fill,
                Children = {layoutTop, listView}
            };
            Content = layout;
        }

        //セル用のテンプレート
        private class MyCell : ViewCell {
            public MyCell() {

                //アイコン
                var icon = new Image();
                icon.WidthRequest = icon.HeightRequest = 50; //アイコンのサイズ
                icon.VerticalOptions = LayoutOptions.Start; //アイコンを行の上に詰めて表示
                icon.SetBinding(Image.SourceProperty, "Icon");

                //名前
                var name = new Label {Font = Font.SystemFontOfSize(12)};
                name.SetBinding(Label.TextProperty, "Name");

                //アカウント名
                var screenName = new Label {Font = Font.SystemFontOfSize(12)};
                screenName.SetBinding(Label.TextProperty, "ScreenName");

                //作成日時
                var createAt = new Label {Font = Font.SystemFontOfSize(8), TextColor = Color.Gray};
                createAt.SetBinding(Label.TextProperty, "CreatedAt");

                //メッセージ本文
                var text = new Label {Font = Font.SystemFontOfSize(10)};
                text.SetBinding(Label.TextProperty, "Text");

                //名前行
                var layoutName = new StackLayout {
                    Orientation = StackOrientation.Horizontal, //横に並べる
                    Children = {name, screenName} //名前とアカウント名を横に並べる
                };

                //サブレイアウト
                var layoutSub = new StackLayout {
                    Spacing = 0, //スペースなし
                    Children = {layoutName, createAt, text} //名前行、作成日時、メッセージを縦に並べる
                };

                View = new StackLayout {
                    Padding = new Thickness(5),
                    Orientation = StackOrientation.Horizontal, //横に並べる
                    Children = {icon, layoutSub} //アイコンとサブレイアウトを横に並べる
                };
            }
            //テキストの長さに応じて行の高さを増やす
            protected override void OnBindingContextChanged() {
                base.OnBindingContextChanged();

                //メッセージ
                var text = ((Tweet)BindingContext).Text;
                //メッセージを改行で区切って、各行の最大文字数を27として行数を計算する(27文字は、日本を基準にしました)
                var row = text.Split('\n').Select(l => l.Length / 27).Select(c => c + 1).Sum();
                Height = 12 + 8 + row * 10 + 20;//名前行、作成日時行、メッセージ行、パディングの合計値
                if (Height < 60) {
                    Height = 60;//列の高さは、最低でも60とする
                }
            }
        }

        private async void Refresh(string keyword) {

            const string ApiKey = "p5n9vK9AxxxxxxxxxxTrCVcZ8";
            const string ApiSecret = "P07hcAAsF5qHxxxxxxxxxxxxxxxxxxxxHdNZgs9Aebfs63";
            const string AccessToke = "109802325-UWdxxxxxxxxxxJxxxxxxxxxxVJGSq4xeQCV";
            const string AccessTokeSecret = "llKQWYFh2xxxxxxxxxxxxxxxxxxxaqA89eFg";


            var tokens = CoreTweet.Tokens.Create(ApiKey,ApiSecret,AccessToke,AccessTokeSecret);

            var result = await tokens.Search.TweetsAsync(count => 100, q => keyword);

            foreach (var tweet in result) {
                _tweets.Add(new Tweet {
                    Text = tweet.Text,
                    Name = tweet.User.Name,
                    ScreenName = tweet.User.ScreenName,
                    CreatedAt = tweet.CreatedAt.ToString("f"),
                    Icon = tweet.User.ProfileImageUrl.ToString()
                });
            }
        }
    }
}


画像付きのツイートを検索する

Androidで画面が遠慮がちになっているし・・・・
@ch3coohさんの所では、Mediaタグの有無で画像付きツイートの検索を紹介されてましたが・・・

力尽きたので、今日はもう寝ます。


[2015.01.21追記]
Androidで画面が遠慮がち」の原因が分かりました。
画面全体のStackLayoutのVerticalOptionsが、Centerになっていました。これをFillに変更することで問題は解消しました。
ある意味、当たり前のオチでした。

var layout = new StackLayout {
    Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0), //iOSのみ上余白
    //VerticalOptions = LayoutOptions.Center,
    VerticalOptions = LayoutOptions.Fill,
    Children = {layoutTop, listView}
};

AndroidのListViewコントロールのデフォルトの高さが、画面の高さより小さかったって事でしょうか・・・

f:id:furuya02:20150121062810p:plain:w200

【 Xamarin 記事一覧 】