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

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

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

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

Q&A

解決済

1回答

854閲覧

Autolayoutをつけるとボタンが巨大化してしまう

退会済みユーザー

退会済みユーザー

総合スコア0

Swift

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

0グッド

0クリップ

投稿2020/11/15 06:09

下記のURLでボイスメモなどで使うようなボタンを作ったのですが、Autolayoutをつけるとボタンが巨大化してしまいました。

https://swift-ios.keicode.com/ios/how-to-create-record-button.php

イメージ説明

Autolayoutなしだと白い円の内側に縮小するのですが、つけるとなぜか拡大します。
上はtableView、下はUIViewで、その中にさらにViewを2つと、ボタンを1つ置いています。
tableView
UIView(baseView)
-> outerCircle
-> innerCircle
-> recordButton
という構成にしてあり、それぞれbaseViewに対して、幅と高さを固定にし、Horizontal in ContainerとVertical in Containerを0にしました。以下、構成図です。
イメージ説明

下記が全文なのですが、オートレイアウトをつけるまでは何も異常がありませんでした。
アニメーションの中でcornerRadiousで縮小するはずなのですが、逆に拡大してしまいます。
これは何かのバグなのか、それともオートレイアウトの何らかの制約があるのでしょうか?

どなたか分かる方がおりましたら、助言をいただけたら幸いです。

import UIKit import AVFoundation class ViewController: UIViewController, AVAudioRecorderDelegate, UITableViewDelegate, UITableViewDataSource { var isRecording = false var recordingSession: AVAudioSession! var audioRecorder: AVAudioRecorder! var audioPlayer: AVAudioPlayer! var w: CGFloat = 0 var h: CGFloat = 0 let d: CGFloat = 50 let l: CGFloat = 28 var numberOfRecords: Int = 0 @IBOutlet weak var recordButton: UIButton! @IBOutlet weak var tableView: UITableView! @IBOutlet weak var baseView: UIView! @IBOutlet weak var outerCircle: UIView! @IBOutlet weak var innerCircle: UIView! @IBAction func record(_ sender: Any) { // Check if we have an active recorder if audioRecorder == nil { numberOfRecords += 1 let fileName = getDirectory().appendingPathComponent("(numberOfRecords).m4a") let settings = [AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 12000, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue] // Start audio recording do { audioRecorder = try AVAudioRecorder(url: fileName, settings: settings) audioRecorder.delegate = self audioRecorder.record() } catch { displayAlert(title: "Ups!!!", message: "Recording failed") } UIView.animate(withDuration: 0.2) { self.recordButton.frame = CGRect(x:(self.w-self.d)/2,y:(self.h-self.d)/2,width: 30,height: 30) self.recordButton.layer.cornerRadius = 3.0 self.recordButton.layer.masksToBounds = true } } else { // Stopping audio recording audioRecorder.stop() audioRecorder = nil UserDefaults.standard.set(numberOfRecords, forKey: "myNumber") tableView.reloadData() UIView.animate(withDuration: 0.2) { self.recordButton.frame = CGRect(x:(self.w-self.self.l)/2,y:(self.h-self.l)/2,width: self.l,height: self.l) self.recordButton.layer.cornerRadius = 25 } } isRecording = !isRecording } override func viewDidLoad() { super.viewDidLoad() // Setting Up Session recordingSession = AVAudioSession.sharedInstance() if let number: Int = UserDefaults.standard.object(forKey: "myNumber") as? Int { numberOfRecords = number } AVAudioSession.sharedInstance().requestRecordPermission { (hasPermission) in if hasPermission{ print("ACCEPTED") } } } override func viewDidAppear(_ animated: Bool) { w = baseView.frame.size.width h = baseView.frame.size.height initRoundCorners() recordButton.layer.masksToBounds = true recordButton.layer.cornerRadius = 25 } // Function that gets path to directory func getDirectory() -> URL { let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) let documentDirectory = paths[0] return documentDirectory } // Function that displays an alert func displayAlert(title: String, message: String){ let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "dismiss", style: .default, handler: nil)) present(alert, animated: true, completion: nil) } func recordButtonCustomize(){ recordButton.layer.masksToBounds = true recordButton.layer.cornerRadius = 25.0 } func initRoundCorners(){ recordButton.layer.masksToBounds = true baseView.layer.masksToBounds = true baseView.layer.cornerRadius = 10 baseView.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner] outerCircle.layer.masksToBounds = true outerCircle.layer.cornerRadius = 31 outerCircle.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) innerCircle.layer.masksToBounds = true innerCircle.layer.cornerRadius = 29 innerCircle.backgroundColor = #colorLiteral(red: 0.1298420429, green: 0.1298461258, blue: 0.1298439503, alpha: 1) } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return numberOfRecords } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = String(indexPath.row + 1) return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let path = getDirectory().appendingPathComponent("(indexPath.row + 1).m4a") do { audioPlayer = try AVAudioPlayer(contentsOf: path) audioPlayer.play() } catch { } } }

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

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

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

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

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

guest

回答1

0

ベストアンサー

AutoLayout をつけると、そちらでつけた制約が優先されるため、frame 値を変更しようといてもうまくいかないと思います。

注意深く記事を読む必要があるのですが、記事中には**「ボタンに対して制約をつける」とは一切書いてありません**。

ボタンについては、記事を要約すると

  • 幅、高さを50くらいにする
  • baseView の配下に置く

としか記載されていません。

「2-1. 丸いボタンの作り方」で「ボタンは適当な場所に配置して、サイズを幅 50、高さ 50 位にしておきます。」と書いてあるじゃん、と思われるでしょうが、この幅、高さは Button をドラッグして適当に決めるか、あるいは Size Inspector の View から設定する必要があります。「制約ではない」 という点にご注意ください。

もっとも、実際はコード中でボタンのサイズを決め打ちしますので、必要なのは baseView の配下に置くことくらいで、サイズは本当に適当でかまいません。

また、本当に参考にしなければいけないのは、記事最後にある完成形のコードなのですが、 kururinnya
さんが参考にされているコードは作成途中として挙げられているコードとなっています。

記事にも掲載されている完成形のコードだと

  • showStartButton()baseView 内におけるボタンの配置と角丸設定
  • showStopButton()baseView 内におけるボタンの配置と角丸設定

を行なっています。

両方とも「ボタンの配置」を行なっていますが、四角形にしたときには外寸が変わった分だけ座標をずらす必要がありますので、その計算も追加されています。

要は、

  • AutoLayout で寸法の変更を行いたいのであれば制約を操作する
  • frame を直接操作するのであれば、その部品だけ AutoLayout を使わない

というのが基本になるかと思いますので、そこを押さえておくといいかと思います。

ちなみに、必要最低限で実証できるコードは次の通りとなります。

Swift

1import UIKit 2 3class ViewController: UIViewController { 4 @IBOutlet weak var recordButton: UIButton! 5 @IBOutlet weak var baseView: UIView! 6 7 var isRecording = false 8 9 // できればもっとわかりやすいプロパティ名が良い 10 var w: CGFloat = 0 11 var h: CGFloat = 0 12 let d: CGFloat = 50 13 let l: CGFloat = 28 14 15 override func viewDidLoad() { 16 super.viewDidLoad() 17 // Do any additional setup after loading the view. 18 } 19 20 override func viewDidAppear(_ animated: Bool) { 21 w = baseView.frame.size.width 22 h = baseView.frame.size.height 23 initRoundCorners() 24 25 //MARK: これが抜けている 26 showStartButton() 27 28 // MARK: 以下は必要ない 29 // initRoundCorners() で設定済み 30 // recordButton.layer.masksToBounds = true 31 // showStartButton() で設定済み 32 // recordButton.layer.cornerRadius = 25 33 } 34 35 // MARK: 抜けてる 36 func showStartButton() { 37 // frame 値を設定しないと、ボタンの初期位置が正確に定まらない 38 recordButton.frame = CGRect(x:(w-d)/2,y:(h-d)/2,width:d,height:d) 39 recordButton.layer.cornerRadius = d/2 40 } 41 42 // MARK: 抜けてる 43 func showStopButton() { 44 recordButton.frame = CGRect(x:(w-l)/2,y:(h-l)/2,width:l,height:l) 45 recordButton.layer.cornerRadius = 3.0 46 } 47 48 func initRoundCorners(){ 49 recordButton.layer.masksToBounds = true 50 51 baseView.layer.masksToBounds = true 52 baseView.layer.cornerRadius = 10 53 baseView.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner] 54 } 55 56 @IBAction func record(_ sender: Any) { 57 // MARK: 検証のため isRecording で判断 58 if !isRecording { 59 UIView.animate(withDuration: 0.2) { 60 // MARK: showStopButton() で処理させる 61 // self.recordButton.frame = CGRect(x:(self.w-self.d)/2,y:(self.h-self.d)/2,width: 30,height: 30) 62 63 // self.recordButton.layer.cornerRadius = 3.0 64 // self.recordButton.layer.masksToBounds = true 65 self.showStopButton() 66 } 67 } else { 68 UIView.animate(withDuration: 0.2) { 69 // MARK: showStartButton() で処理させる 70 // self.recordButton.frame = CGRect(x:(self.w-self.self.l)/2,y:(self.h-self.l)/2,width: self.l,height: self.l) 71 // self.recordButton.layer.cornerRadius = 25 72 self.showStartButton() 73 } 74 } 75 // true <-> false をトグルさせる 76 isRecording.toggle() 77 } 78}

投稿2020/11/15 08:32

TsukubaDepot

総合スコア5086

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問