質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

2136閲覧

SwiftUI arrayを使って時間の経過ごとに説明文(テキスト)を入れ替える方法

Tomzy

総合スコア104

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2021/05/18 07:48

編集2021/05/31 00:33

質問の概要

健康法に関するアプリを開発中です。5秒ごとにテキスト内容(120個)を変更したいと考えています。if文で5秒ごとの膨大なコードを書いて切り替えることは成功していますが、より簡単なコードにするために、arrayの中に、テキストを記入して、順番に表示させることを考えています。id, id + 1, id + 2, id + 3を使って4個のテキストが順番に表示することは成功していますので、更に20秒ごとにidをid + 1にして、5x4x30=600秒間に120個のテキストを入れ替える方法を教えてください。

対策案と問題点

この課題である「arrayを使って時間の経過ごとに説明文(テキスト)を入れ替える方法」について、英文、和文の検索を相当数行いましたが、サンプル案は見つかりませんでした。そこで、下記のコードを考えましたが、問題点がでて行き詰まりました。即ち、20秒までは、5秒ごとに下記4枚の画面が変化し、タイトル下の黄色い枠内の文字が変わります。20秒後はまた、同じ画面の繰り返しになります。20秒以後も同様に画面が変わるように、最後の段階で、id = id + 1のコードを入れました。そうすると、ビルドはできますが、”error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions"というエラーがでて止まります。コメントアウトするとビルドもでき4個だけのテキストが繰り返し表示されます。

現在のコード

import SwiftUI //中略 //第1画面形状 struct ContentView01 : View { let array: [String] = ["text001", "text002", "text003", "text004", "text005", "text006",//中略 ] let id: Int = 0 func hitomawari() -> Double { self.stopWatchManager.secondsElapsed.truncatingRemainder(dividingBy: 20) } var body: some View { NavigationView { VStack { VStack(spacing: 1) { //01 解説テキスト Group { //秒数で変わる解説文 if 0 <= self.hitomawari() && self.hitomawari() < 5.0 { Text((array[id]) as String)         } else if 5 <= self.hitomawari() && self.hitomawari() < 10.0 { Text((array[id+1]) as String) } else if 10 <= self.hitomawari() && self.hitomawari() < 15.0 { Text((array[id+2]) as String) } else if 15 <= self.hitomawari() && self.hitomawari() < 20.0 { Text((array[id+3]) as String) //20秒ごとにidを1づつ増やす // id = id + 1 // このコードがあると、ビルドはできますが、”error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions"というエラーがでて止まります。 //コメントアウトするとビルドもでき4個だけのテキストは表示されます。 } } .padding() .border(Color.yellow, width: 5) .cornerRadius(3) } //中略

現在表示される画面

時間の経過により5秒ごとに下記4枚の画像のとおりに変化します。20秒後も同じ画像の繰り返しになります。

イメージ説明

イメージ説明

イメージ説明

イメージ説明

ご参考事項

テキスト部分は英文と日本文でつくり、上記のtext001などのキーワードで
Localizable.stringsを使って表示する予定です。Text("")でのLocalizable.stringsの使用方法は分かっていますが、
arrayでの表示は、異なるようですので、別途挑戦したいと思っています。

よろしくお願いします。

環境

現在の環境は下記のとおりです。

  • MacBook Pro (15-inch, 2016)
  • Big Sur OS11.3.1
  • Xcode Version  12.5 (12E262)
  • SwiftUI

TakeOneさんのアンサーにもとづき実装したコード

//第1画面上段に記載する解説文章英語、日本語120個をLocalizedStringKeyで整列させるためのArray定義 let array:[LocalizedStringKey] = [ "text001", "text002", "text003", "text004", "text005", //中略 ] //秒針が5秒進むごとにArrayのidを上げて指定する順番を定義する func getTextId() -> Int { //経過時間を5秒で割ったIntを算出 let elapsed = self.stopWatchManager.secondsElapsed/5 //その計算結果をIntにする let elapsedInt = Int(elapsed) //その結果を120で割った残りを算出し、121回目以降Arrayが元にもどるようにする let index = elapsedInt % 120 //表示の時にArrayの順番を示す return index } //中略 //01上段の120個の解説テキストをArrayで表示する。getTexIdは順番。121個目以降は元に戻り繰り返す。 Group { Text(array[getTextId()]) .padding() .border(Color.yellow, width: 5) .cornerRadius(3) }

表示された画面

イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tomato879241

2021/05/18 08:17

ただそれぞれのケース(0秒、5秒、...)で Text((array[id]) as String) の下に id += 1 と書けば済むのではないでしょうか?
MasakiHori

2021/05/18 09:23

@State property wrapperを使う場面のような気がしますね
Tomzy

2021/05/18 09:58

早速レスポンスありがとうございました。最初は、そのようにしました。しかし、”error: the compiler is unable to type-check this expression ・・がでるので、5秒x4のみ、直接Text((array[id+1]) as String)のように書いて成功しました。その後、シミュレーターのリセットや他の複雑なコードをコメントアウトなどいろいろ試しましたが、解決しませんでした。id + 1やid = id + 1とコードを追加しただけで、ビルド後上記のエラーが発生する状態です。
Tomzy

2021/05/19 02:38

MasakiHoriさんへ、@State property wrapperについて、 https://blog.personal-factory.com/2021/01/23/how-to-use-propertywrapper-in-swiftui/ を読んだりして勉強していますが、まだ、分かっていません。 取り敢えず、idの定義を @State private var id = 0 に変えたりしながら、原案のコードをいじっていますが、エラーの状況は変わっていません。 xAxisさんのコードも参考にしながら解決策を見いだしたいと思います。今後とも、ご指導ください。
Tomzy

2021/05/31 00:13

結局、本文の追記どおりのコードで動くようになりました。ご協力ありがとうございました。
guest

回答2

0

ベストアンサー

現状のコードで5秒ごとに4枚の画面が変化するところまでできているのであれば、self.hitomawari() が返した値に応じてTextを表示することはできているのだと思います。

そして、hitomawari メソッドの内容は、self.stopWatchManager.secondsElapsed を20で割った余りを返す処理に
なっているので、stopWatchManagersecondsElapsedを参照して経過秒数を取得することが既にできているのだろうと思います。

であれば、hitomawari メソッドの代わりに、self.stopWatchManager.secondsElapsed の値に応じた配列番号を取得するメソッドを作成し、例えばそのメソッド名を getTextId という名前にしたなら、テキストを表示する箇所は単純にText(array[getTextId()]) のように記述するだけで、配列番号に対応した文字をarrayから得て、それを表示することができると思います。

arrayに入っているものが、実際に表示したい文字列ではなくて、ローカライズ文字列のキーを定義しているのであれば、Stringの配列ではなく、LocalizedStringKeyの配列として定義すれば、そのキーに対応したローカライズ文字列が表示されるようになると思います。

投稿2021/05/27 02:51

TakeOne

総合スコア6299

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tomzy

2021/05/30 23:31

TakeOneさんへ こんにちは。アンサーありがとうございました。お陰様で思ったとおりに5秒ごとに、120個のテキストをArrayで表示することができました。ローカライズのキーワードにより、日本語で表示できました。具体的なコードを本文の追記に整理して記載したいと思います。121回目よりArrayの最初に戻ることもできました。
guest

0

エラーの発生原因については自分ではちょっと分かりませんでした。なのでとりあえず希望通り動くものを用意してみました。

swift

1 2 3import SwiftUI 4 5struct ContentView: View { 6 7 @State var index: Int = 0 8 9 let textArray: [String] = ["0", "1", "2", "3", "4", "5", "6"] 10 11 var body: some View { 12 13 VStack { 14 Button(action: { 15 16 Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true, block: {_ in 17 //ここで任意のタイミングで動くタイマーを用意します。今回はindexを増やしたいのでrepeatsはtrueで。withTimeintervalで何秒に一回動くかをセットします。blockの中はクロージャで 18 if index == 6 { 19 //このコードだと7つしか配列がないのでindexが6になった時最初の0に戻してあげます。でないとクラッシュします 20 index = 0 21 } else { 22 index = index + 1 23 //index += 1 でもOKです。 24 } 25 26 }) 27 28 }) { 29 Text("Start") 30 } 31 Text(textArray[index]) 32 } 33 34 } 35} 36 37struct ContentView_Previews: PreviewProvider { 38 static var previews: some View { 39 ContentView(index: 0) 40 } 41} 42

投稿2021/05/18 09:31

編集2021/05/18 09:47
xAxis

総合スコア1349

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tomzy

2021/05/18 09:59

ありがとうございました。私のアプリに応用して、結果をご報告します。
Tomzy

2021/05/19 02:32

@State private var id = 0 にして新設ボタンを付けたまま、組み込みましたら動きました。テキストも変化することがわかりました。トリガーをこの新設ボタンではなく、スタートボタンにすることと、スピードを変更させる場合の対応を考えたいと思います。また、ご報告します。
xAxis

2021/05/19 03:55

ひとまず動いたようで良かったです。また何かありましたら聞いてください。答えられる範囲でお答えしますね。
Tomzy

2021/05/19 06:55

ありがとうございます。それにしても、”error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions" は難しいですね。今まで通っていたコードが急にエラーになり、コメントアウトすると復活したり、勉強にはなりますが、試行錯誤の連続です。
xAxis

2021/05/19 09:37

エラーで式を解体しろと言われてもじゃあどこを?ってなっちゃったりしますよね。検索して答えが出てくる時はいいですが大体はそこからもう一歩考えないといけなかったりして。
Tomzy

2021/05/31 00:11

結局、本文の追記どおりのコードで動くようになりました。ご協力ありがとうございました。
xAxis

2021/05/31 04:06

何はともあれ無事動いてよかったです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問