SwiftChartをSwiftUIで使う

SwiftUI

入力されたデータのグラフ表示は必須ですよね。

グラフ表示のライブラリとしてSwiftChartというライブラリがあるのですが、それをSwiftUI化するまでの手順のメモです。

LineViewを使いたいので、LineView特化型です。
# と思って作って行ったのですが、結果的に特にLineView限定になっていません。

CocoaPodでインストール

SwiftChartは、まだSwift Package Managerに対応していないので、CocoaPodを使ってインストールします。

  • プロジェクトのディレクトリで、% pod init
  • 作成されたPodfileに、 pod ‘SwiftChart’ を追加
  • プロジェクトのディレクトリで、% pod install or update
  • .xcworkspaceを使って、Xcodeを起動

まず、ここで、コンパイルがおかしくなっていないか確認します。

XCode11.4では、1箇所、Deprecatedと言われたコードがあったので、言われるままに修正しました。

UIViewRepresentableでWrapする

まずは、以下のようなコードで、静的なデータを表示することができるかを確認しました。

きちんと別のSwiftUI要素と矛盾しないことを確認しました。

ただ、このままだと、データも内部で生成してますし、タッチされたときの動作も何もないです。
ということで、すこしづつできることを増やしていきます。

# 今回は、データの動的な変更でグラフが変形されることは目指しません。タッチしたときにデータの詳細を表示できることがゴールです。

ChartSeriesを外部から渡す

ChartSeriesを外から渡すようにしようとも考えたのですが、外部からChartSeries(表示対象とするデータ)を取得するClosureを渡すことにしようかと。

こうすることで、アプリのデータ構造、SwiftChartでのデータ構造のどちらも理解しなければいけない箇所をClosure中に閉じ込めることができます。
つまり、アプリ本体は、SwiftChartが使うChartSeriesに対してindependentになり、LineGraphViewもどのようにデータを取得するかについてindependentにできます。

タッチした箇所のデータ詳細の表示

調べてみるとChartDelegateなるプロトコルがタッチ操作への対応するためのプロトコルでした。

UIViewRepresentableでは、Coordinatorを作るのが定石ですので、以下のように追加しました。

Chartでは、タッチ中には、didTouchChartが呼ばれ続け、タッチがおわるとdidEndTouchingChartが呼ばれるようです。

didTouchChartの引数

xは、グラフ中のX値、leftは、表示領域中のX値です。(詳細は、SwiftChartのソースを参照のこと)
Indexesは、最初の値は、入力とした何番目のSeriesか、2番目の値は、そのSeriesの中の何番目かです。
これらの情報を使って、”chart.valueForSeries(seriesIndex, atIndex: dataIndex)”とするとChart本体から、値を取得することができます。

この情報を使って、頂点付近をタッチされた時に、その値を数値として表示することができます。

Chartは、その他いろいろカスタマイズ可能

上記の方法で、上位からデータを渡してそのデータを表示するところまではできるようになります。
SwiftChartはグラフの色や軸についてもカスタマイズできるので、それぞれのデータを上記のようなclosureで渡すもよし、@ObservableObjectで渡すのもありです。
いずれにしても、UIKit向けに作られたコンポーネントが簡単にSwiftUIと共存することができます。

注意
上記では、UIViewを継承しているものを再利用をしたので、UIViewRepresentableを使用していますが、UIViewControllerを継承しているものを再利用するならば、UIViewControllerRepresentableを使うことになります。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です