125
93

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Swift(iOS)でイケてるトースト・バナー・ポップアップを導入する (SwiftEntryKit)

Last updated at Posted at 2020-01-26

SwiftEntryKit

トーストやポップアップ、プッシュ通知のようなビューを簡単に導入できるすごいライブラリ SwiftEntryKit をこの記事で紹介する。いくつか同様のライブラリ(Toast-Swiftなど)を試したが、SwiftEntryKitが圧倒的にイケてるUIUXを作れると感じた。イメージは以下の通り。

Toasts Notes Floats Popups
toasts_example notes_example floats_example popups_example
Alerts Forms Rating More...
alerts_example forms_example rating_example custom_example

インストール

ここに丁寧に書いてあるのでここでは言及しない。CocoaPodsやCarthageで入れるだけ。

使い方のイメージ

import SwiftEntryKit

///

func test() {
    var attributes = EKAttributes.bottomFloat // bottomFloat以外に様々なタイプがある
    // プロパティを設定していく
    // attributes.xxx = xxx
    // たとえば以下の通り
    attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(UIColor.red), EKColor(UIColor.orange)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
    attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
    attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
    attributes.statusBar = .light
    attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
    attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.bounds.width), height: .intrinsic)

    // EKNotificationMessageViewなど、EKxxxViewを作ってattributesとともにSwiftEntryKitに渡す
    // UIFont() は任意の形に変更する必要がある
    let title = EKProperty.LabelContent(text: "Sample Notification", style: .init(font: UIFont(), color: .standardContent))
    let description = EKProperty.LabelContent(text: "Body message", style: .init(font: UIFont(), color: .standardContent))
    let image = EKProperty.ImageContent(image: UIImage(named: "some image"), size: CGSize(width: 35, height: 35))
    let simpleMessage = EKSimpleMessage(image: image, title: title, description: description)
    let notificationMessage = EKNotificationMessage(simpleMessage: simpleMessage)
    let contentView = EKNotificationMessageView(with: notificationMessage)

    // あとはSwiftEntryKit.displayを呼ぶだけ
    SwiftEntryKit.display(entry: contentView, using: attributes)
}

このライブラリでは、ビューのトップ、中央、ボトムの3つの位置(top / center / bottom)を選択でき、ビューのタイプは以下のような感じで10個以上定義されている。位置とビューのタイプを組み合わせて使うことになる。

  • EKAlertMessageView
  • EKFormMessageView
  • EKNotificationMessageView
  • EKNoteMessageView
  • EKPopUpMessageView
  • EKRatingMessageView

iOSのプッシュ通知のようなバナーを表示する

struct NotificationBanner {
    static func show(title: String, body: String, image: UIImage) {
        var attributes = EKAttributes.topFloat
        attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(UIColor.red), EKColor(UIColor.orange)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
        attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
        attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
        attributes.statusBar = .light
        attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
        attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.bounds.width), height: .intrinsic)

        // UIFont() は任意の形に変更する必要がある        
        let title = EKProperty.LabelContent(text: title, style: .init(font: UIFont(), color: .white))
        let description = EKProperty.LabelContent(text: body, style: .init(font: UIFont(), color: .white))
        let image = EKProperty.ImageContent(image: image, size: CGSize(width: 35, height: 35))
        let simpleMessage = EKSimpleMessage(image: image, title: title, description: description)
        let notificationMessage = EKNotificationMessage(simpleMessage: simpleMessage)

        let contentView = EKNotificationMessageView(with: notificationMessage)
        SwiftEntryKit.display(entry: contentView, using: attributes)
    }
}

利用するのはこんな感じ。

NotificationBanner.show(title: "Notification title", body: "Notification body", image: UIImage(named: "xxx"))

お洒落なアラートを表示する

struct Alert {
    // ここではアクションが一つの場合
    static func show(title: String, body: String, image: UIImage, action: @escaping () -> Void) {
        var attributes = EKAttributes.topFloat
        attributes.displayDuration = .infinity
        attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(UIColor.purple), EKColor(UIColor.blue)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
        attributes.screenBackground = .visualEffect(style: .prominent)
        attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
        attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
        attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
        attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.bounds.width), height: .intrinsic)
        // これがないとアクションが実行されない
        attributes.entryInteraction = .absorbTouches

        // UIFont() は任意の形に変更する必要がある
        let title = EKProperty.LabelContent(text: title, style: .init(font: UIFont(), color: .white))
        let description = EKProperty.LabelContent(text: body, style: .init(font: UIFont(), color: .white))
        let image = EKProperty.ImageContent(image: image, size: CGSize(width: 35, height: 35))
        let simpleMessage = EKSimpleMessage(image: image, title: title, description: description)        

        let label = EKProperty.LabelContent(text: "OK", style: .init(font: UIFont(), color: .black))
        let button = EKProperty.ButtonContent(label: label, backgroundColor: .white, highlightedBackgroundColor: .standardBackground) {
            // dismissを自分で呼ばないとビューが消えない
            SwiftEntryKit.dismiss()
            action()
        }        
        let content = EKProperty.ButtonBarContent(with: [button], separatorColor: EKColor(UIColor.black), expandAnimatedly: true)

        let alertMessage = EKAlertMessage(simpleMessage: simpleMessage, buttonBarContent: content)
        let view = EKAlertMessageView(with: alertMessage)
        
        SwiftEntryKit.display(entry: view, using: attributes)
    }
}

利用するのはこんな感じ。

Alert.show(title: "Alert title", body: "Alert body") {
    print("tapped!!")
}

ポップアップを表示する

struct Popup {
    static func show(title: String, body: String, action: @escaping () -> Void) {
        var attributes = EKAttributes.centerFloat
        attributes.displayDuration = .infinity
        attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(UIColor.purple), EKColor(UIColor.blue)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
        attributes.screenBackground = .visualEffect(style: .prominent)
        attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
        attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
        attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
        attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.bounds.width), height: .intrinsic)
        // これがないとアクションが実行されない
        attributes.entryInteraction = .absorbTouches
        // UIFont() は任意の形に変更する必要がある
        let title = EKProperty.LabelContent(text: title, style: .init(font: UIFont(), color: .white))
        let description = EKProperty.LabelContent(text: body, style: .init(font: UIFont(), color: .white))
        
        let label = EKProperty.LabelContent(text: "OK", style: .init(font: UIFont(), color: .black))
        let button = EKProperty.ButtonContent(label: label, backgroundColor: .white, highlightedBackgroundColor: .standardBackground)
        let action: EKPopUpMessage.EKPopUpMessageAction = {
            SwiftEntryKit.dismiss()
            // ここにボタン押下時のアクションを入れることができる
            action()
        }
        let popupMessage = EKPopUpMessage(title: title, description: description, button: button, action: action)
        let view = EKPopUpMessageView(with: popupMessage)
        
        SwiftEntryKit.display(entry: view, using: attributes)
    }
}

利用するのはこんな感じ。

Popup.show(title: "Popup title", body: "Popup body") {
    print("tapped!!")
}

フォーム付きのポップアップを表示する

struct Form {
    // フォームが1つの場合
    static func show(title: String, placeholder: String = "", image: UIImage, action: @escaping (String) -> Void) {
        var attributes = EKAttributes.centerFloat
        attributes.displayDuration = .infinity
        attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(UIColor.purple), EKColor(UIColor.blue)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
        attributes.screenBackground = .visualEffect(style: .prominent)
        attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
        attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
        attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
        attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.bounds.width), height: .intrinsic)
        // これがないとアクションが実行されない
        attributes.entryInteraction = .absorbTouches

        let white = EKColor(UIColor.white)
        let black = EKColor(UIColor.black)
        let gray = EKColor(UIColor.gray)
        
        let whiteStyle = EKProperty.LabelStyle(font: UIFont(), color: white)
        let blackStyle = EKProperty.LabelStyle(font: UIFont(), color: black)
        
        let title = EKProperty.LabelContent(text: title, style: whiteStyle)
        let ok = EKProperty.LabelContent(text: "OK", style: blackStyle)
        let placeholder = EKProperty.LabelContent(text: placeholder, style: whiteStyle)
        
        let content = EKProperty.TextFieldContent(keyboardType: .asciiCapable, placeholder: placeholder, tintColor: white, displayMode: .inferred, textStyle: whiteStyle, leadingImage: image, bottomBorderColor: white)
        
        let button = EKProperty.ButtonContent(label: ok, backgroundColor: .white, highlightedBackgroundColor: gtray) {
            SwiftEntryKit.dismiss()
            action(content.textContent)
        }
        
        let view = EKFormMessageView(with: title, textFieldsContent: [content], buttonContent: button)
        
        SwiftEntryKit.display(entry: view, using: attributes)
    }
}

利用するのはこんな感じ。

Form.show(title: "Form title", body: "Form body") { value in
    print("input value: \(value)")
}

まとめ

他にもToast、Note、Rating等のビューが用意されているが、同様の要領で利用できる。繰り返しになるが、EKNotificationMessageViewなど、EKxxxViewを作ってattributesとともにSwiftEntryKitに渡せば良い。

125
93
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
125
93

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?