20191011のiOSに関する記事は9件です。

ReactorKitでFirestoreをListenする方法

概要

ReactorKitを使ったプロジェクトでFirestoreを使うことになったので、Pringを用いて実装しました。

環境

実装

UserというモデルをFirestoreから取得してくるという設定です。

Reactor側

Action, Mutation, State, mutate, reduceはやるだけって感じです。
ポイントはdataSourceを以下のように用意して、

private let dataSource: DataSource<User>?

setupDataSource()内でDataSourcelisten()してやることです。
この時.onの中でself?.action.onNext(.updateUsers(users))することで、Firestoreから取得したデータをReactorのストリームにうまく取り込んでます。

private func setupDataSource() {
    dataSource = User.query.dataSource()
        .on { [weak self] _, _ in
            guard let users = self?.dataSource?.documents else { return }
            self?.action.onNext(.updateUsers(users))
        }
        .listen()
}

全実装は以下のようになります。

import ReactorKit
import RxSwift
import Pring

final class UserListReactor: Reactor {
    enum Action {
        case updateUsers([User])
    }

    enum Mutation {
        case setUsers([User])
    }

    struct State {
        var users: [User] = []
    }

    // MARK: - Variables

    let initialState = State()
    private let dataSource: DataSource<User>?

    // MARK: - Initializer

    init() {
        setupDataSource()
    }

    // MARK: - Setup Methods

    private func setupDataSource() {
        dataSource = User.query.dataSource()
            .on { [weak self] _, _ in
                guard let users = self?.dataSource?.documents else { return }
                self?.action.onNext(.updateUsers(users))
            }
            .listen()
    }

    // MARK: - Reactor Methods

    func mutate(action: Action) -> Observable<Mutation> {
        switch action {
        case let .updateUsers(users):
            return .just(Mutation.setUsers(users))
        }
    }

    func reduce(state: State, mutation: Mutation) -> State {
        var state = state
        switch mutation {
        case let .setUsers(users):
            state.users = users
        }
        return state
    }
}

ViewController側

いつも通りbind(reactor:)内でUserListReactor.State.usersbindしてやれば終わりです。

import UIKit
import RxSwift
import ReactorKit

final class UserListViewController: UIViewController, View {
    // MARK: - Variables

    var disposeBag = DisposeBag()
    ...
    // MARK: - Bind Methods

    func bind(reactor: UserListReactor) {
        // State
        reactor.state.map { $0.users }
            .distinctUntilChanged()
            .bind { users in
                // tableView or collectionViewの更新
            }
            .disposed(by: disposeBag)
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Firebase めちゃ便利!Onekilo (iosアプリ)リリースしました!

Firebase めちゃ便利!! Onekiloリリースしました!

Outline

  • 自己紹介
  • Onekiloとは?
  • Firebase のおすすめ点(もうみんな知ってるか笑)
  • 最後に

 自己紹介

初めまして!
立命館大学理工学部3年の葛上です!watnowの代表をしています!!
Twitterフォローしてください!Facebookも友達になってください!

メンバー

ios 2人
UI/UXデザイナー 1人
動画作成 1人
の計4人で開発しました。

ios 開発歴はまだ2年目で、今まで開発したサービスは5つほどしかありません。
Firebase に関しては、一年前にRealtimeDatabase 少し使ってtwitterみたいなのを使ったくらいです!

Onekilo とは?

今回作成したサービスがOnekiloになります!
抽象的ではありますが、

「今すぐ」何かするって当たり前になってきてるな

と思い、足掛かりとしてマッチングアプリを作りました。
概要としては 1km圏内の人とランダム通話ができると言う事です。
マッチング界はほとんどレッドオーシャン状態になっていますが、
すんごいニッチなターゲット選定をしています笑 そこが売りであり、僕たちの強みでもあり弱みでもあります笑
IMG_642E445D70BF-1.jpeg

onekiloで使用したFirebaseの機能

(本音を言うとアプリに関係なく全て活用したかったです笑)

  • Authentication
    • ユーザー登録する際に用いました
  • Cloud Firestore
    • Database として使用しました
  • Storage
    • 画像の保存や引っ張てくるのに用いました。
  • Remote Config
    • 強制的にバージョンをアップデートを行うために用いました!(すんごい便利)
  • Cloud Messaging
    • ユーザーに通知を送るために使用しました。
  • アナリティクス(全て)
    • 実際にユーザーの反応を見るのにすごく便利です。
他にもML Kit とか使いたかったです。。。

上記の使い方などは要望があれば別で描こうと思います。

最後に

実は今年の4月くらいにOnekiloのアイデアが自分の頭の中ででていました。

こんなん誰も使わんやろと思いながら3ヶ月くらいすぎて、Cyber Agentやリクルートのインターンに参加させていただいた際にちゃんと事業戦略練ればいけるんじゃないかと期待してくれたのが今回僕が動く結果になりました。

ありがとうございます。

「マッチングサービスはレッドオーシャン」
「半径1kmのマッチングはニッチすぎる」

と指摘されることは多々ありますが、自分の事業戦略を通して勝ち筋通りに進めたらいいなと思います。
もっと書きたいことはありますが、このような話はnoteに記しますので興味ある方は読んでください。。!

最後にベータ版ではありますが、Onkilo のインストールをよろしくお願いいたします。

最後まで読んでいただきありがとうございます。

watnow
mememe
代表
葛上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSでハートのボタンアニメーションをつくる

先日「いいね!」的なハートのボタンアニメーションを作る機会がありまして。

先輩がライブラリ公開しているものを参考にしつつ、
https://qiita.com/darquro/items/c5cdf7dbcad1d5bb0188

自分はライブラリではなく、自作で、
@IBDesignable@IBInspectableを使って
ハートボタンとそのアニメーションを作ってみましたので、その備忘録。

開発環境

Mac OS Mojave 10.14.6
Xcode 11.0
Swift 5

つくりたいもの

  • ハートの画像2枚をボタン押下で切り替える
  • ボタン押下時(Highlight時)にハートをちょっと小さくする
  • ボタン押下後(Touch up inside)にハートをちょっと大きくする

ハートの画像2枚をボタン押下で切り替える

アニメーションとは付加機能。
まずアニメーションなしで、つくりたいものを実現します。

他にも方法はあると思いますが、今回はハートの画像2枚をボタン押下で切り替えます。

@IBDesignable@IBInspectableを使った汎用的なボタン

@IBDesignable@IBInspectableは非常に便利です。
(SwiftUIの世の波とは逆行してる感!)

コードである程度の設定を書いておくと、
Storyboardでカスタマイズが容易になります。

まずImageButtonという汎用的なボタンを設定します。

import UIKit

@IBDesignable
final class ImageButton: UIButton {

    @IBInspectable var unselectedImage: UIImage = UIImage()
    @IBInspectable var selectedImage: UIImage = UIImage()

    public var selectedStatus: Bool = false {
        didSet {
            setupImageView()
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        setupImageView()
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setupImageView()
        setNeedsDisplay()
    }

    private func setupImageView() {
        self.setImage(self.selectedStatus ? self.selectedImage : self.unselectedImage, for: .normal)
        self.setImage(self.selectedStatus ? self.selectedImage : self.unselectedImage, for: .highlighted)
    }
}

@IBInspectableで指定した、unselectedImageselectedImage は、
Storyboard上でカスタマイズできるようになります。

Storyboardで設定

Storyboardでボタンを配置して、

上記のように、Custom Classに作成したImageButtonを設定すると、

このように、unselectedImageselectedImage
好きな画像を設定できるようになります。

つまりImageButtonはハートボタン以外にも利用できるので、便利感ありますね。
以下の画像を設定します。

  • unselectedImage
  • selectedImage
  • DefaultのImage <- 忘れないように

アクションを設定

あとはボタンのクリック動作をハンドリングして、処理を書きます。
※Storyboardとコードを結びつけるとこは省略。

@IBOutlet private weak var likeButton: ImageButton!
@IBAction private func clickLikeButton(_ sender: Any) {
    likeButton.selectedStatus = !likeButton.selectedStatus
}

画像切り替え 完成

これでアニメーションのない、ハートボタンが完成です。

ハート押下時にアニメーションを

今回は CASpringAnimation を利用します。
ばねっぽいAnimationを表現しやすいと聞いたので。

今回アニメーションを付けるのは2箇所あります。

  • ボタン押下時(Highlight時)にハートをちょっと小さくする
  • ボタン押下後(Touch up inside)にハートをちょっと大きくする

ボタン押下時(Highlight時)にハートをちょっと小さくする

方法は色々あると思いますが、自分は以下のコードで実現しました。
isHighlighted でボタンが押されている状態かを識別します。

override var isHighlighted: Bool {
    didSet {
        if isHighlighted {
            if imageView?.layer.animation(forKey: "reduced-size") == nil {
                let animation = CASpringAnimation(keyPath: "transform.scale")
                animation.duration = 0.05 // animation時間
                animation.fromValue = 1.0 // animation前サイズ
                animation.toValue = 0.95 // animation後サイズ
                animation.mass = 0.1 // 質量
                animation.autoreverses = false // 自動でfromの値に戻らない
                animation.initialVelocity = 40.0 // 初速度
                animation.damping = 1.0 // 硬さ
                animation.stiffness = 40.0 // バネの弾性力
                animation.isRemovedOnCompletion = false // animation動作後に完了状態としない
                animation.fillMode = .forwards // 一方向モード。fromの形状に戻らない
                imageView?.layer.add(animation, forKey: "reduced-size")
            }
        }
    }
}

ポイントは以下。

  • mass initialVelocity damping stiffness は動作を見てなんとなく値決め
  • 押下中にサイズが戻ってしまわないように、autoreverses isRemovedOnCompletion はfalse、fillMode.forward
  • animationは1回だけ実行にしたいので、animationが既に実行されているかどうかの判別式を記載 if imageView?.layer.animation(forKey: "reduced-size") == nil
  • animation実行判別のために、任意のkey名reduced-sizeを設定

これでボタン押下時のAnimationは実現できました。
しかし、これでは imageView?.layer.add(animation, …)で、追加された
animationがremoveされていません。それについては後述。

ボタン押下後(Touch up inside)にハートをちょっと大きくする

こちらも方法は色々あるかと思いますが、今回は上記で設定したsetupImageView()
funcにanimationを記載することで実現しました。

private func setupImageView() {
    self.setImage(self.selectedStatus ? self.selectedImage : self.unselectedImage, for: .normal)
    self.setImage(self.selectedStatus ? self.selectedImage : self.unselectedImage, for: .highlighted)
    let animation = CASpringAnimation(keyPath: "transform.scale")
    animation.duration = 0.3 // animation時間
    animation.fromValue = 0.95 // animation前サイズ
    animation.toValue = 1.0 // animation前サイズ
    animation.mass = 0.6 // 質量
    animation.initialVelocity = 40.0 // 初速度
    animation.damping = 3.0 // 硬さ
    animation.stiffness = 40.0 // バネの弾性力
    imageView?.layer.add(animation, forKey: nil)
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
        self.imageView?.layer.removeAllAnimations() // highlightのAnimationも含め、removeする
    }
}

既述したもの以外のポイントは以下。

  • animationが全て完了したらremoveする必要があるので、animation時間が経過したらremoveを実施 self.imageView?.layer.removeAllAnimations()

animationのremoveに関してはもっと良い方法があるかも...
指摘などあればぜひコメントお願いしますm(_ _)m

完成

これでアニメーション付きのハートが完成しました。

まとめ

CASpringAnimationについて、
@IBDesignable@IBInspectableについて、
詳細の説明は省略しました。参考資料をご確認頂ければと。

参考

https://qiita.com/kaway/items/b9e85403a4d78c11f8df
http://www.cl9.info/entry/2018/05/26/175246
https://qiita.com/h-nag/items/7af47ea665332c3ac1bf
https://qiita.com/tasaiii725/items/c70bf648242b061e0734
https://qiita.com/son_s/items/7ca2acf690d10f9fd1b7

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

@IBDesignableと@IBInspectableで汎用的なButtonを

こんな感じのボタンを作りたいとき。

普通に favoriteButton として作成しても良いですが、
「他のボタンにも同じ構成で作れる汎用的なボタンにしたい」
という時に@IBDesignable@IBInspectableが便利です。

@IBDesignable@IBInspectableとは

@IBDesignableとは?
@IBInspectableとは?
と聞かれるとなんて答えてよいか難しいのですが、

@IBDesignable@IBInspectableを使うと、
事前に作成しておいたViewを、Storyboard上で適用できる、カスタマイズできる
ものです。

例を示します。

final class RoundedCornerButton: UIButton {

    @IBInspectable var iconImage: UIImage = UIImage()
}

このようにUIButtonを継承するRoundedCornerButtonクラスを定義して、
Storyboard上に設定したボタンのCustomクラスに、

このようにRoundedCornerButtonを設定すると、

@IBInspectableで設定したiconImageをStoryboard上で設定できる、
というものです。

RoundedCornerButton

細かく書くより、コード全体を載せたいと思います。
こんな感じのボタンを作成します。

RoundedCornerButton:

import UIKit

@IBDesignable
final class RoundedCornerButton: UIButton {

    @IBInspectable var iconImage: UIImage = UIImage()
    @IBInspectable var unselectedText: String = "未選択"
    @IBInspectable var selectedText: String = "選択済み"

    @IBInspectable var unselectedBackgroundColor: UIColor = UIColor.systemTeal
    @IBInspectable var unselectedShadowColor: UIColor =  UIColor.ocean
    @IBInspectable var unselectedBorderColor: UIColor = UIColor.clear
    @IBInspectable var selectedBackgroundColor: UIColor = UIColor.baseGray
    @IBInspectable var selectedShadowColor: UIColor = UIColor.gray
    @IBInspectable var selectedBorderColor: UIColor = UIColor.clear

    // ボタンがselectされているかどうかの変数
    private(set) var selectedStatus: Bool = false

    // ボタンが凹む前のX座標
    private lazy var originalX: CGFloat = {
        return self.layer.position.x
    }()

    // ボタンが凹む前のY座標
    private lazy var originalY: CGFloat = {
        return self.layer.position.y
    }()

    private lazy var stackView: UIStackView = {
        let stackView = UIStackView(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
        stackView.translatesAutoresizingMaskIntoConstraints = false // autoLayoutをONに
        stackView.alignment = .center
        stackView.distribution = .fill
        stackView.axis = .horizontal
        stackView.spacing = 4.0
        stackView.backgroundColor = UIColor.clear
        stackView.isUserInteractionEnabled = false // stackView部分をタップしてもボタンが反映するように
        return stackView
    }()

    private lazy var iconImageView: UIImageView = {
        let iconImageView = UIImageView(image: iconImage)
        iconImageView.contentMode = .scaleAspectFit // 画像そのままに縦横比に表示
        iconImageView.widthAnchor.constraint(equalToConstant: 32.0).isActive = true
        return iconImageView
    }()

    private lazy var textLabel: UILabel = {
        let width = stackView.frame.width - iconImageView.frame.width
        let textLabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: frame.height))
        textLabel.text = unselectedText
        textLabel.textAlignment = .center
        textLabel.textColor = UIColor(hex: "#4A4A4A")
        textLabel.font = UIFont.boldSystemFont(ofSize: 16.0)
        return textLabel
    }()

    override func awakeFromNib() {
        super.awakeFromNib()
        setupLayer()
        setupViews()
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setupLayer()
        setupViews()
        setNeedsDisplay()
    }

    // Highlight時にボタンが凹んだように見せるため、layerの位置変更・影なしに
    override var isHighlighted: Bool {
        didSet {
            layer.position = CGPoint(x: originalX, y: isHighlighted ? originalY+2.0 : originalY)
            layer.shadowOffset = isHighlighted ? CGSize(width: 0.0, height: 0.0) : CGSize(width: 0.0, height: 2.0)
        }
    }

    private func setupLayer() {
        setStatus(selectedStatus)
        layer.borderWidth = 1.0 // 枠線の長さを定義
        layer.cornerRadius = 4.0 // 角丸に
        layer.shadowOpacity = 1.0 // 影を表示する
        layer.shadowRadius = 0.0 // ぼやけ影を非表示
    }

    private func setupViews() {
        self.addSubview(stackView) // buttonのviewにstackViewを載せる
        stackView.addArrangedSubview(iconImageView) // iconImageViewをstackViewに載せる
        stackView.addArrangedSubview(textLabel) // textLabelをstackViewに載せる
        stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20.0).isActive = true // stackViewの左端をbuttonのviewの左端から20離す
        stackView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
    }
}

// MARK: public
extension RoundedCornerButton {
    func setStatus(_ status: Bool) {
        selectedStatus = status
        layer.backgroundColor = status ? selectedBackgroundColor.cgColor : unselectedBackgroundColor.cgColor
        layer.shadowColor = status ? selectedShadowColor.cgColor : unselectedShadowColor.cgColor
        layer.borderColor = status ? selectedBorderColor.cgColor : unselectedBorderColor.cgColor
        layer.shadowOffset = CGSize(width: 0.0, height: status ? 3.0 : 2.0) // 影の長さ
        textLabel.text = status ? selectedText : unselectedText
    }
}

ポイントは以下。

  • レイアウトの配置は、Storyboardでエラーが出ないようにAutoLayout設定する感覚で。
  • ボタンの上にViewを載せると、ボタンが押せなくなってしまうので、isUserInteractionEnabledをfalseに。

favoriteButtonにRoundedCornerButtonを適用

StoryboardでfavoriteButtonにRoundedCornerButtonをCustom Classに設定。

@IBInspectableで設けた項目をそれぞれ設定します。

favoriteButtonについて、コードで以下のようにアクションを設定。

@IBOutlet private weak var favoriteButton: RoundedCornerButton!
@IBAction private func clickFavoriteButton(_ sender: Any) {
    favoriteButton.setStatus(!favoriteButton.selectedStatus)
}

以上で完成です。

まとめ

StackViewを用いている@IBDesignable@IBInspectableの例が
あまりネット記事になかったこともあり、記事として記載してみました。ぜひ参考にしてみてください。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[saml2aws] error authenticating to IdP: page is missing saml assertion

問題

いつも使っているaws-authでAWSにログインしようとすると、以下のエラーが返してきた。

error authenticating to IdP: page is missing saml assertion

背景

  • MacOS 10.14.6

対応

brew upgrade saml2aws

原因

認証画面が変わった気がします。ちなみに、iOSだと発生しますが、Androidは発生してないようです。


aws-auth

一発ログイン

saml2aws login -a idp_account_name —username=username --password=‘password' --role='arn:aws:iam::31xxxxx:role/Administrator' --skip-prompt
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ios13のWKWebViewのWebRTC対応状況まとめ

はじめに

iOS12までは、iOSのWebRTC対応状況はSafariのみで、WKWebViewでは対応していませんでした。
この記事では、iOS13になって対応されているか検証を行いました。

結論

iOS12と変わらず、getUserMediaが実装されていないため動きませんでした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOS13からAirDrop痴漢ができなくなった。Appleの痴漢対策か!?

以前、AirDrop痴漢に気をつけましょうという記事を書きましたが
https://qiita.com/a-nishimura/items/b1f709126227a4876146

なんとiOS13からAirDropの仕様変更がありました。
画像を受け入れるまでプレビューされなくなりました。

ということで、わいせつな画像を送りつける「AirDrop痴漢」ができなくなったのです。
これはまさかAppleのAirDrop痴漢対策なのでしょうか。
はたまたただの仕様変更なのでしょうか。
理由は定かではないのですが、犯罪に使われるのもよくないのでコンプライアンス的な背景もあったのかもしれませんね。

ただ、プレビュー機能自体はとても便利なものだったので、
その便利なものを悪用する人がいて、仕様が変わっていくのは少し残念ですね。

うちのブログでも書いているのでよかったらぜひご覧ください
https://www.wow-creators.com/2019/07/12/【まとめ】airdrop痴漢やってみた/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Objective-CでprivateメソッドのUnit Testの作り方

普段開発時に、自分が作ったメソッドに対して、Unit Testで動作確認したいけど、
privateメソッドは他のクラスからアクセスできない、Unit Testを動くために、一時的ヘッダークラスに定義するのも微妙です。

Objective-Cのカテゴリを利用することで他のクラスからprivateメソッドへのアクセスも可能です。

テストしたいダミークラスSomeClassを用意する

SomeClass.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SomeClass : NSObject

@end

NS_ASSUME_NONNULL_END

今回はヘッダーファイルに特に何も定義していない。

SomeClass.m

#import "SomeClass.h"
#import <os/log.h>

@implementation SomeClass

- (BOOL)privateMethod {
    os_log(OS_LOG_DEFAULT, "This is a private method");
    return YES;
}

@end

実装ファイルにYESを返すメソッドを1つ用意します。
コンソールにメッセージを1行出力します。

Unit Testのクラスを作る

新規作成からUnit Test Case Classを選択します。
Screen Shot 2019-10-11 at 10.44.06.png

クラス名はわかりやすいように、今回はUTT_SomeClassTestにします。
Screen Shot 2019-10-11 at 10.44.27.png

※ここからは重要

Unit Testクラスの一番最初にテストしたいクラスのカテゴリを作ります。
カテゴリの中にテストしたいprivateメソッドを定義します。

@interface SomeClass (Test)

- (BOOL)privateMethod;

@end

SomeClassはテストしたいクラスのクラス名、括弧に定義した「Test」はテスト用のカテゴリを明記するため、他のカテゴリも問題ないです。

Unit Testの全文は下記のようになります。

#import <XCTest/XCTest.h>
#import "SomeClass.h"

@interface SomeClass (Test)

- (BOOL)privateMethod;

@end

@interface UTT_SomeClassTest : XCTestCase

@end

@implementation UTT_SomeClassTest

- (void)setUp {
    // Put setup code here. This method is called before the invocation of each test method in the class.
    [super setUp];
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    [super tearDown];
}

- (void)testPrivateMethod {
    SomeClass *someClass = [[SomeClass alloc] init];
    XCTAssertTrue([someClass privateMethod]);
}

@end

最後、テストを実行する

実施結果は問題なく通りました。

Screen Shot 2019-10-11 at 10.45.43.png

コンソール上にもメッセージが出力されています。

Test Suite 'Selected tests' started at 2019-10-11 10:19:26.658
Test Suite 'Unit Test TestTests.xctest' started at 2019-10-11 10:19:26.659
Test Suite 'UTT_SomeClassTest' started at 2019-10-11 10:19:26.659
Test Case '-[UTT_SomeClassTest testPrivateMethod]' started.
2019-10-11 10:19:26.671954+0900 Unit Test Test[10250:2834238] This is a private method
Test Case '-[UTT_SomeClassTest testPrivateMethod]' passed (0.013 seconds).

テストクラスからもprivateメソッドのアクセスも可能になりました!

参考サイト
https://stackoverflow.com/questions/18354788/unit-testing-private-method-objective-c

Thanks Abizern, saved my day.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Xcode11]StoryboardでSuperViewへのEqualWidth,EqualHeightができなくなった時の解決法

はじめに

Xcode11でstoryboardを使っていて、ViewをSuperViewと同じ横幅にしようと思ったのですが、ViewをSuperViewへドラッグしたところEqualWidthsは見当たりませんでした、

問題

Xcode11以前はStoryboardでViewなどをドラッグしてSuperViewに合わせると

qii.png

このようなメニューが出てきて、EqualWidthsを選択するとEqual Widths Constraintをつけることができました

スクリーンショット 2019-10-10 23.42.10.png

しかし、Xcode11では同じ操作をするとこのような画面になり、メニューからEqualWidths,EqualHeights,Aspect Ratioが消えてしまいました。

スクリーンショット 2019-10-10 23.45.08.png

回避策

先ほどSuperViewへドラッグした操作をSafeAreaに変更すると、EqualWidths,EqualHeights,Aspect Ratioが出現するので選択します。

スクリーンショット 2019-10-10 23.46.02.png

そうするとこのような感じになりますので、Second Itemの欄からSuperViewを選択してあげると

スクリーンショット 2019-10-10 23.46.14.png

SuperViewと同じ高さにしてあげることができました

スクリーンショット 2019-10-10 23.46.34.png

参考リンク

Xcode 11 Add "Equal Width to Superview" Constraint?

Cannot equal height to Superview in Xcode 11

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む