Xamarin.FormsでLink表現してみた( ̄ー+ ̄)
今回はXamarin.FormsでLink表現をおこなってみました。
LinkerLabelって名前にしています。
完成動画はこちら
sleepyandhungry1984.tumblr.comコードはこちら
スマホアプリでリンク表現が正しいのか・・・
..(/^^)/ ソレハコッチニオイトイテ
表現手段が増えることは良い事です。
利用方法
まずは、このLinkerLabelをどのように使うかのコードを示します。
<shared:LinkerLabel Text="{Binding BaseText}" FontSize="15" VerticalOptions="Center" HorizontalTextAlignment="Start" HorizontalOptions="Center" ItemsSource="{Binding LinkWords}" Command="{Binding LinkCommand}"/>
LinkerLabelはLabelを継承していますので基本的にはLabelです。
Labelとの違いはItemsSourceとCommandのBindablePropertyを持っている事です。
ItemsSourceにIEnumerable
ItemsSourceは当然INotifyCollectionChangedに対応していますのでItemsSourceを変更すればLink表現も追従します。
今回のサンプルのViewModelはLinkerLabel/MainPageViewModel.cs at master · yuka1984/LinkerLabel · GitHubですが画面から入力した文字列をLinkWordsコレクションに追加する事でLink表現が変化しています。
では実装方法を見ていきましょう。
共通実装部分
LinkerLabel/LinkerLabel.cs at master · yuka1984/LinkerLabel · GitHub
Labelを継承してItemsSourceやCommand、LinkColorのプロパティを増やしてそれに対する実装をおこなっています。
ItemsSourceが変更された際には
private void UpdateMatchWords() { var txt = Text; var buffer = new List<MatchWord>(); var sources = ItemsSource.Cast<string>().ToList(); foreach (var source in sources) { var matches = Regex.Matches(txt, source); if (matches.Count > 0) foreach (Match match in matches) if (!buffer.Any(x => x.StartPosition <= match.Index && x.EndPositon >= match.Index)) buffer.Add(new MatchWord { Word = source, StartPosition = match.Index }); } _matchWords = buffer; OnPropertyChanged(nameof(MatchWords)); }
こんな感じでTextからLink箇所を抽出して配列化してinternalなプロパティMatchWordsを設定しています。
Rendererの方でMatchWordsの変更を受け取ってプラットフォーム毎にゴニョゴニョする感じになります。
Androidの実装
コードはこちら
LinkerLabel/LinkerLabelRenderer.cs at master · yuka1984/LinkerLabel · GitHub
ほぼ記事そのままの実装なので詳細はこちらの記事を見てください。
要約するとSpannableStringというクラスを使うことでリンク表現できますよ~ってことです。
iOSの実装
コードはこちら
LinkerLabel/LinkerLabelRenderer.cs at master · yuka1984/LinkerLabel · GitHub
ほぼ記事そのままの実装なので詳細はこちらの記事を見てください。
要約すると
NSMutableAttributedStringというクラスを使うことでリンク表現できますよ~
Tap検出はUITextView.GetClosestPositionToPointできますよ~
でもLabelのiOSでのプラットフォームコントロールはUILabelなのでできませんよ~
なので仮想のUITextViewを作ってtap検出しましたよ~
っていう感じです。
Xamarin iOSでNSLocationInRange関数が見つからなくて代替手段を考えるのに少し時間がかかりました。
おわりに
今回はしませんでしたがURL検出などを行うようにすればAndroidのLinkifyみたいなこともXamarin.Formsでも可能かもしれませんね。
最近はXamarin Androidでの開発の勉強をしていてDroidKaigi2017アプリをXamarin Androidで書くとどうなるか?みたいな研究をしているのですが、これが本当に難しくて今まで私がXamarin Nativeに思っていた事と現実にはかなりの差があって、考えを改めながら色々と作っている最中です。
ずっとローカルで作業していたのですが最近GitHub上に公開しました。
GitHub - yuka1984/DroidKaigi2017forXamarin
まだまだなのですが、少しずつXamarin Androidでの開発を習得していきたいと思います。
それではまた~(^^)/