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

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

ただいまの
回答率

88.59%

複数のボタンを押すたびにそれぞれon,offに切り替える方法

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 574

pepper0

score 20

プロジェクトにjsonファイルを組み込み、そのファイル内のプロパティの値をforEachで回し、値の数だけボタンを作りました。そこに、ボタンそれぞれにボタンを押すたびにボタンテキストを切り替えたいと考えています。
ボタンアクションがそもそも間違っているのは分かります。
何か良い方法はあるでしょうか?
下記に作成段階のコードとjsonファイルを記しました。

import UIKit
//jsonの使用
import Foundation
//話させる
import AVFoundation

class ViewController: UIViewController , UIScrollViewDelegate , UITextFieldDelegate {

    var num:Int = 170
    var wid:CGFloat = 0
    var size:Int = 0
    var talker = AVSpeechSynthesizer()
    var count = 0


    struct Sample: Codable {

        let sam1: [String]
        let sam2: [String]
        // let sam3: [String]
    }


    //オブジェクトのデータをjson文字列として返している
    func getJSONData() throws -> Data? {
        guard let path = Bundle.main.path(forResource: "sample", ofType: "json") else { return nil }

        let url = URL(fileURLWithPath: path)

        return try Data(contentsOf: url)

    }

    override func viewDidLoad() {
        super.viewDidLoad()

        if UIDevice.current.userInterfaceIdiom == .phone {

            //画面のスクロール
            let scrollView = UIScrollView()
            scrollView.backgroundColor = UIColor.white
            scrollView.frame.size = CGSize(width: view.frame.width, height: view.frame.height)
            scrollView.center = self.view.center
            scrollView.contentSize = CGSize(width: view.frame.width, height: 1000)
            scrollView.bounces = false
            scrollView.indicatorStyle = .default
            scrollView.scrollIndicatorInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
            scrollView.delegate = self

            self.view.addSubview(scrollView)


            //画面上部のラベル
            guard let data1 = try? getJSONData() else { return }

            guard let sam1 = try? JSONDecoder().decode(Sample.self, from: data1!) else { return }

            sam1.sam1.forEach({(sample) in
                let label = UILabel()
                label.textAlignment = NSTextAlignment.center
                label.text = "\(sample)"
                label.frame = CGRect(x: 150, y: 150, width: 300, height: 30)
                label.layer.position = CGPoint(x: self.view.frame.width/2, y:100)
                label.textColor = UIColor.black
                label.backgroundColor = UIColor(red: 0.3, green: 0.4, blue: 0.7, alpha: 0.1)
                scrollView.addSubview(label)

                //話させる
                let utterance = AVSpeechUtterance(string:sample)
                utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")
                self.talker.speak(utterance)

            })


            guard let data2 = try? getJSONData() else { return }

            guard let sam2 = try? JSONDecoder().decode(Sample.self, from: data2!) else { return }


            //jsonデータ出力、ボタンの生成
            sam2.sam2.forEach({(sample) in

                let button = UIButton()
                button.frame = CGRect(x: 25+(size*60)+(size*10), y: 370, width: 300, height: 60)
                button.layer.position = CGPoint(x:self.view.frame.width/2,y:170 + wid)
                button.setTitleColor(UIColor.black, for: UIControlState.normal)
                button.backgroundColor = UIColor(red: 0.3, green: 0.7, blue: 0.6, alpha: 0.1)
                button.layer.borderColor = UIColor(red: 0.3, green: 0.6, blue: 0.5, alpha: 1).cgColor
                button.layer.cornerRadius = 15
                button.layer.shadowOffset = CGSize(width: 2,height: 2)
                button.setTitle("\(sample)",for: UIControlState.normal)

                //ボタンで実行するメソッド
                button.addTarget(self, action: #selector(buttonTapped(_:)), for: UIControlEvents.touchUpInside)

                /*
                 button.setTitle("\(sample)☑️",for: UIControlState.highlighted)
                 button.setTitleColor(UIColor.red, for: UIControlState.selected)
                 */

                scrollView.addSubview(button)

                wid = wid + 70

                size = size+1
                // i=i+1

            })


            //テキストフィールドの生成
            var textField :UITextField!
            textField = UITextField()
            textField.delegate = self
            textField.frame = CGRect(x: self.view.frame.width/5  , y: 170 + wid, width: 250 , height: 60)
            textField.placeholder = "その他"
            textField.borderStyle = UITextBorderStyle.roundedRect
            textField.textAlignment = NSTextAlignment.left
            textField.keyboardType = UIKeyboardType.default
            textField.returnKeyType = UIReturnKeyType.go
            textField.clearButtonMode = UITextFieldViewMode.never
            scrollView.addSubview(textField)

            wid = wid + 200

            //送信ボタン
            let sentButton :UIButton!
            sentButton = UIButton(type: .custom)
            sentButton.frame = CGRect(x: self.view.frame.width/5  , y: 170 + wid, width: 100 , height: 45)
            sentButton.layer.position = CGPoint(x:self.view.frame.width/2,y:170 + wid)
            sentButton.setTitle("送信",for: UIControlState.normal)
            sentButton.backgroundColor = UIColor(red: 0.5, green: 0.6, blue: 0.7, alpha: 0.2)
            sentButton.setTitleColor(.black, for: .normal)
            sentButton.layer.shadowOffset = CGSize(width: 2,height: 2)
            sentButton.layer.cornerRadius = 13
            scrollView.addSubview(sentButton)
        }

        if UIDevice.current.userInterfaceIdiom == .pad{

        }
    }

    //ボタンアクション
    **この部分が問題です**
    @objc func buttonTapped(_ sender: AnyObject){
        print("ボタンの情報:\(sender)")

        count += 1
        if(count%2 == 0){
            button.text = "\(sample)☑️"
        }
        else{
            button.text = "\(sample)☑️"

        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    //キーボードを下げる
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true

    }
}
{
//sam2をforEachで回してボタンを作っています
    "sam1" : ["どんな症状ですか?"],
    "sam2" : ["エラーが出ています","プログラムが動きません","実行できません"]
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

まあまあややこしいけど、僕がやるならこう。

enum State {
    case on, off

    mutating func toggle()  {

        switch self {
        case .on: self = .off
        case .off: self = .on
        }
    }
}

struct StatedText {
    private var state: State
    private let onText: String
    private let offText: String

    init(onText: String, offText: String) {

        self.state = .on
        self.onText = onText
        self.offText = offText
    }

    mutating func toggle()  {

        state.toggle()
    }

    var text: String {

        switch state {
        case .on: return onText
        case .off: return offText
        }
    }
}

class StatedButton {
    private var statedText: StatedText
    let button: UIButton

    func toggle() {

        statedText.toggle()
//        button.text = statedText.text
        button.setTitle(statedText.text,for: UIControlState.normal)
    }

    init(button: UIButton, onText: String, offText: String) {

        self.button= button
        self.statedText = StatedText(onText: onText, offText: offText)
    }
}
class ViewController: UIViewController , UIScrollViewDelegate , UITextFieldDelegate {
    ...
    ...
    var buttons: [StatedButton] = []

    ....
    ....


    override func viewDidLoad() {
        ...
        ...
        buttons = sam1.sam1.map { sample in
            let button = UIButton()
            ...
            ...

            return StatedButton(button: button, onText: "オンの時のテキスト", offText: "オフの時のテキスト")
        }

        ...
        ...

    }

    ...
    ...

    @objc func buttonTapped(_ sender: UIButton) {

        buttons
            .filter { statedButton in sender == statedButton.button }
            .first
            .map { statedButton in statedButton.toggle() }
    }

    ...
    ...
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/29 18:36

    修正ありがとうございます。
    再び質問なのですが、class StatedButton の
    button.text = statedText.text
    の部分のエラーだけが直せないです。何回も申し訳ないですが、よければご教授願えますか?

    キャンセル

  • 2018/12/03 15:59

    遅くなりました。修正時に見落としがありました。新たに修正しました。

    キャンセル

  • 2018/12/11 15:25

    返信遅れました。
    自力で修正することは出来ましたが、再度修正していただきありがとうございました。
    とても参考になりました。

    キャンセル

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

  • ただいまの回答率 88.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る