20191112のSwiftに関する記事は10件です。

数値の丸め方について

数値を丸めたい!

UISliderのvalueを取得した際、小数第5位まで表示されてしまったため数値の丸め方についてまとめました。

方法1 formatを使用する

howToChangeDigits
let number = 12.34567

print(String(format: "%.0f", number))   // -> "12"
print(String(format: "%.1f", number))   // -> "12.3"
print(String(format: "%.2f", number))   // -> "12.35"
print(String(format: "%.3f", number))   // -> "12.346"

結果より、四捨五入して丸められていることがわかります。
丸めた後のデータ型は、String型になります。

方法2 round()を使用する

howToChangeDigits
let number = 12.34567

print(round(number)                  // -> 12.0
print(round(number * 10) / 10)       // -> 12.3
print(round(number * 100) / 100)     // -> 12.35
print(round(number * 1000) / 1000)   // -> 12.346

formatを使用した時と同様に四捨五入されます。
丸めた後のデータ型はDouble型またはFloat型になります。特に型を指定せずにnumberを定義した場合はDouble型になります。
round()の代わりにfloor()を使用すると切り捨て、ceil()を使用すると切り上げて丸めることができます。

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

IPhoneでカメラを使ったアプリの基本(swift)

https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/avcam_building_a_camera_app

UIImagePickerController

→実装がすごい簡単
できることは少ない

AVCaptureStillImageOutput

→iOS10でdeprecated

AVCapturePhotoOutput

→iOS10以降
・API Reference - AVCapturePhotoOutput
・LivePhotoなどの撮影が可能
・UIImagePickerControllerと比べると実装が複雑

AVCaptureVideoDataOutput

→iOS4以降
動画撮影を行う

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

ドッグフーディング用にiOSアプリからslackにフェードバックをする方法

Debug中のアプリをSlackに簡単にスクショとか動画をメッセージ付きで投稿できる
AppFeedback-iosを入れる

SDKの導入

Carthageでの導入

Cartfileに以下を追記する

github "https://github.com/yahoojapan/AppFeedback-ios"
carthage update

Build PhasesのLink Binary With LibrariesからAppFeedback.frameworkを追加

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

リリースするバージョンには表示しないようにするため、
Build PhasesからRun Scriptで以下を追加

CopyFrameworks.png

if ["${CONFIGURATION}" != "Release" ]; then
  /usr/local/bin/carthage copy-frameworks
fi

Input Files

$(SRCROOT)/Carthage/Build/iOS/AppFeedback.framework

Bridging HeaderにSDKを追加

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

まだ、Briding Headerがない場合は適当にObject-Cのファイルを追加するとBridging Headerを追加するかどうか聞かれるので追加する。その後Obj-Cのファイルは削除

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

Briding HeadeファイルにAppFeedBackを追加

#import <AppFeedback/AppFeedback.h>

実装

AppDelegateに以下のように記載

import AppFeedback


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // ……

    #if DEBUG
        AppFeedback.configure(withSlackToken:"<your token>", slackChannel:"<slack channel id>")
    #endif

    // ……
}

もし、SceneDelegateに対応している場合

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        AppFeedback.configure(withSlackToken: "foo", slackChannel: "hoge")
        AppFeedback.readyFeedbackGesture()
        AppFeedback.readyScreenShot()
        guard let _ = (scene as? UIWindowScene) else { return }
    }

slackのtokenはログインした状態でここのcreate tokenから取得する。
チャンネルIDはslackのチャンネルを右クリックでコピーすると分かります。

これで表示完了!!
スクリーンショット 2019-11-05 17.54.53.png

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

ドッグフーディング用にiOSアプリからslackにフィードバックをする方法

Debug中のアプリをSlackに簡単にスクショとか動画をメッセージ付きで投稿できる
AppFeedback-iosを入れる

SDKの導入

Carthageでの導入

Cartfileに以下を追記する

github "https://github.com/yahoojapan/AppFeedback-ios"
carthage update

Build PhasesのLink Binary With LibrariesからAppFeedback.frameworkを追加

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

リリースするバージョンには表示しないようにするため、
Build PhasesからRun Scriptで以下を追加

CopyFrameworks.png

if ["${CONFIGURATION}" != "Release" ]; then
  /usr/local/bin/carthage copy-frameworks
fi

Input Files

$(SRCROOT)/Carthage/Build/iOS/AppFeedback.framework

Bridging HeaderにSDKを追加

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

まだ、Briding Headerがない場合は適当にObject-Cのファイルを追加するとBridging Headerを追加するかどうか聞かれるので追加する。その後Obj-Cのファイルは削除

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

Briding HeadeファイルにAppFeedBackを追加

#import <AppFeedback/AppFeedback.h>

実装

AppDelegateに以下のように記載

import AppFeedback


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // ……

    #if DEBUG
        AppFeedback.configure(withSlackToken:"<your token>", slackChannel:"<slack channel id>")
    #endif

    // ……
}

もし、SceneDelegateに対応している場合

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        AppFeedback.configure(withSlackToken: "foo", slackChannel: "hoge")
        AppFeedback.readyFeedbackGesture()
        AppFeedback.readyScreenShot()
        guard let _ = (scene as? UIWindowScene) else { return }
    }

slackのtokenはログインした状態でここのcreate tokenから取得する。
チャンネルIDはslackのチャンネルを右クリックでコピーすると分かります。

これで表示完了!!
スクリーンショット 2019-11-05 17.54.53.png

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

【SwiftUI】画像のリサイズ

画像の表示

struct ContentView: View {
    var body: some View {
        Image("Image", bundle: .main)
    }
}

スクリーンショット 2019-11-12 15.03.57.png

大きすぎるのでリサイズ

struct ContentView: View {
    var body: some View {
        Image("Image", bundle: .main)
            .frame(width: 50.0, height: 50.0, alignment: .leading)
    }
}

ちゃんとリサイズされません

スクリーンショット 2019-11-12 15.05.16.png

.resizable()を付ける

Image をリサイズする際には .resizable() をつけなければならないみたいです。

struct ContentView: View {
    var body: some View {
        Image("Image", bundle: .main)
            .resizable()
            .frame(width: 50.0, height: 50.0, alignment: .leading)
    }
}

スクリーンショット 2019-11-12 15.05.34.png

これでリサイズされました。

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

swift言語でSwipe風のiOS Buttonを作って見る

デザイナーさんからSwipe風のスライド動作で実現できるiOSボタンを作って欲しい、
要望があって、カスタマイズしたUIButtonを実現して見た。

1) 一旦、カスタマイズするButtonはSwipeButtonとして、UIViewを継承することにする。
SwipeButton.swift
import UIKit
@IBDesignable class SwipeButton: UIView {

}
2) 次に、表示使用とするラベルと背景、移動Buttonの部品等を定義して置く。
SwipeButton.swift
import UIKit
@IBDesignable class SwipeButton: UIView {
    @IBInspectable var textColor : UIColor = UIColor.white
    @IBInspectable var frontColor : UIColor = UIColor.yellow
    @IBInspectable var groundColor : UIColor = UIColor.gray
    @IBInspectable var backColor : UIColor = UIColor.clear
    @IBInspectable var textFont : UIFont = UIFont.systemFont(ofSize: 16)

    public lazy var textLabel: UILabel = { [unowned self] in
        let label = UILabel()
        label.textColor = textColor
        label.backgroundColor = .clear
        label.numberOfLines = 1
        label.textAlignment = .center
        label.font = textFont
        return label
        }()

    public lazy var bar: UIView = { [unowned self] in
        let view = UIView()
        view.backgroundColor = groundColor
        return view
        }()

    public lazy var button: RoundView = { [unowned self] in
        let view = RoundView()
        view.backgroundColor = frontColor
        return view
        }()
3) SwipeButtonが初期化する時の各SubView部品を格納するよう、初期化処理をする
SwipeButton.swift
import UIKit
@IBDesignable class SwipeButton: UIView {
    public var text: String? = nil //ヒントテキスト

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.commInt()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.commInt()
    }

    public convenience init(_ text: String?) {
        self.init()
        self.text = text
        self.commInt()
    }

    private func commInt() {
        self.backgroundColor = backColor

        self.addSubview(bar)
        self.bar.addSubview(textLabel)
        self.addSubview(button)
        self.bringSubviewToFront(button)
    }
4) UIViewのlayoutSubviewsメソットをoverrideして以下の動作を実装する
SwipeButton.swift
    public var isRightToLeft: Bool = true //どの方向に移動するか定義
    public var isEnabled: Bool = true //ユーザが操作できるか定義
    private var startFrame:CGRect! //Buttonが移動する前のFrame情報
    private var turnedFrame:CGRect!//Buttonが移動した後のFrame情報
    @IBInspectable var barHeight: CGFloat = 40.0 //bar部品の高さ

    override func layoutSubviews() {
        super.layoutSubviews()

        let maxWidth: CGFloat = self.frame.width
        let maxHeight: CGFloat = self.frame.height
        if barHeight > maxHeight {
            barHeight = maxHeight
        }
        if barHeight < 10 {
            textLabel.isHidden = true
        }
        self.bar.frame = CGRect(x: 0, y: (maxHeight - barHeight) / 2, width: maxWidth, height: barHeight)
        if self.text != nil,!textLabel.isHidden {
            textLabel.text = self.text
            textLabel.frame = CGRect(origin: .zero, size: bar.frame.size)
        } else {
            textLabel.frame = CGRect.zero
        }
        let leftFrame = CGRect(x: 0, y: 0, width: maxHeight, height: maxHeight)
        let rightFrame  = CGRect(x: (maxWidth - maxHeight), y: 0, width: maxHeight, height: maxHeight)

        if isRightToLeft {
            self.startFrame = rightFrame
            self.turnedFrame = leftFrame
        } else {
            self.startFrame = leftFrame
            self.turnedFrame = rightFrame
        }
        button.frame = startFrame

        if isEnabled {
            button.isUserInteractionEnabled = true
        } else {
            button.isUserInteractionEnabled = false
        }
        self.corner(bar)
        self.corner(button)
        if borderWidth > 0 {
            self.bouder(bar, width: borderWidth, color: borderColor)
        }
5) 上記のcornerメソットとbouderメソットについて、エクステンションして実装しておく
SwipeButton.swift
extension SwipeButton {
    func bouder(_ view: UIView, width: CGFloat, color: UIColor) {
        view.layer.masksToBounds = true
        view.layer.borderColor = color.cgColor
        view.layer.borderWidth = width
    }

    func corner(_ view: UIView, radius: CGFloat = 0) {
        view.layer.masksToBounds = true
        view.layer.cornerRadius = (radius > 0) ? radius : (view.frame.height / 2)
    }
}
6) buttonがSwipeする動作に対して、動画効果のメソットをエクステンションして実装しておく
SwipeButton.swift
    // Swipeした後の部品色について、定義する
    @IBInspectable var swipedFrontColor : UIColor = UIColor.red
    @IBInspectable var swipedGroundColor : UIColor = UIColor.darkGray
    @IBInspectable var swipedTextColor : UIColor = UIColor.systemYellow
    //Swipeした後,表示しようとするテキストを定義
    public var swipedText: String?

extension SwipeButton {
    // 前に進む動画処理
    func swipeToGo() {
        UIView.animate(withDuration: self.duration, animations: {
            self.button.frame = self.turnedFrame
        }){ (completed) in
            self.button.backgroundColor = self.swipedFrontColor
            self.bar.backgroundColor = self.swipedGroundColor
            self.textLabel.textColor = self.swipedTextColor
            if let swipedText = self.swipedText {
                self.textLabel.text = swipedText
            }
        }
    }
    // 元に戻る動画処理
    func swipeToBack() {
        UIView.animate(withDuration: self.duration, animations: {
            self.button.frame = self.startFrame
        }){ (completed) in
            self.button.backgroundColor = self.frontColor
            self.bar.backgroundColor = self.groundColor
            self.textLabel.textColor = self.textColor
            if let text = self.text {
                self.textLabel.text = text
            } else {
                self.textLabel.text = nil
            }
        }
    }
}
7) これからはSwipe移動するbuttonクラスを実装する
SwipeButton.swift
protocol RoundViewDelegate: class {
    // ButtongaタッチされたらDelegateプロトコルで通知するメソットを定義しておく
    func roundViewTouchesEnded() -> Void
}
class RoundView: UIView {
    weak var delegate: RoundViewDelegate?

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.isUserInteractionEnabled = true
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
8) UIViewのタッチイベントを検知するtouchesBegan、touchesMoved、touchesEndedメソットをそれぞれ、overrideして、以下の動作を実装する
SwipeButton.swift
    weak var delegate: RoundViewDelegate? // タッチイベントのDelegate
    public var touchSize: CGSize! // 移動範囲
    private var locationInitialTouch: CGPoint! //最初位置

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else{
            return
        }
        let location = touch.location(in: self)
        print(" Began:(\(location.x), \(location.y))")

        locationInitialTouch = location
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {
            return
        }
        let location = touch.location(in: self)
        if location.x < 0 || location.x > touchSize.width { return }
        if location.y < 0 || location.y > touchSize.height { return }
        print(" Moved:(\(location.x), \(location.y))")
        let f = frame.offsetBy(dx: location.x - locationInitialTouch.x, dy: 0)
        if (f.minX >= 0 && f.maxX <= touchSize.width) {
            frame = f
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        defer {
            delegate?.roundViewTouchesEnded()
        }
        guard let touch = touches.first else{
            return
        }
        let location = touch.location(in: self)
        if location.x < 0 || location.x > touchSize.width {
            return
        }
        if location.y < 0 || location.y > touchSize.height {
            return
        }
        print(" Ended:(\(location.x), \(location.y))")
        let f = frame.offsetBy(dx: location.x - locationInitialTouch.x, dy: 0)
        if (f.minX >= 0 && f.maxX <= touchSize.width) {
            frame = f
        }
    }

9) SwipeButtonクラスがRoundViewDelegateが受けた場合の処理を実装する。
SwipeButton.swift
// MARK: - RoundViewDelegate
extension SwipeButton : RoundViewDelegate{
    func roundViewTouchesEnded() {
        if self.button.center.x > (self.frame.width / 2) {
            if self.isRightToLeft {
                swipeToBack()
            } else {
                swipeToGo()
            }
        } else {
            if self.isRightToLeft {
                swipeToGo()
            } else {
                swipeToBack()
            }
        }
    }
}
10) SwipeButtonのlayoutSubviewsメソットにbuttonの移動範囲touchSizeを指定する。
SwipeButton.swift
  override func layoutSubviews() {
        super.layoutSubviews()

        button.touchSize = self.frame.size
10) 最後、作られたSwipeButton部品を使用して見よう
SwipeButton.swift
class ViewController: UIViewController {
    var swipeButton : SwipeButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        setupSwipeButton()
       }

    func setupSwipeButton() {
        if swipeButton == nil {
            self.swipeButton = SwipeButton(frame: CGRect(x:40, y:200, width: 300,height:50))
            swipeButton.isRightToLeft = true
            swipeButton.text = "すぐ買う"
            swipeButton.swipedText = "購入いたしました"
            self.view.addSubview(self.swipeButton)
        }
    }

Swipe後の動作処理については、この文対象以外で一旦、割愛させていただきます。

以上、簡単な説明となりますが、乱文で失礼致します。

iOS、Androidアプリの制作なら、hq7781@gmail.comまで、
法人並みに、信頼且つ満足できる製品を納品いたします

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

Swipe風のiOS Buttonを作って見る(swift編)

デザイナーさんからSwipe風のスライド動作で実現できるiOSボタンを作って欲しい、
要望があって、カスタマイズしたUIButtonを実現して見た。

1) 一旦、カスタマイズするButtonはSwipeButtonとして、UIViewを継承することにする。
SwipeButton.swift
import UIKit
@IBDesignable class SwipeButton: UIView {

}
2) 次に、表示使用とするラベルと背景、移動Buttonの部品等を定義して置く。
SwipeButton.swift
import UIKit
@IBDesignable class SwipeButton: UIView {
    @IBInspectable var textColor : UIColor = UIColor.white
    @IBInspectable var frontColor : UIColor = UIColor.yellow
    @IBInspectable var groundColor : UIColor = UIColor.gray
    @IBInspectable var backColor : UIColor = UIColor.clear
    @IBInspectable var textFont : UIFont = UIFont.systemFont(ofSize: 16)

    public lazy var textLabel: UILabel = { [unowned self] in
        let label = UILabel()
        label.textColor = textColor
        label.backgroundColor = .clear
        label.numberOfLines = 1
        label.textAlignment = .center
        label.font = textFont
        return label
        }()

    public lazy var bar: UIView = { [unowned self] in
        let view = UIView()
        view.backgroundColor = groundColor
        return view
        }()

    public lazy var button: RoundView = { [unowned self] in
        let view = RoundView()
        view.backgroundColor = frontColor
        return view
        }()
3) SwipeButtonが初期化する時の各SubView部品を格納するよう、初期化処理をする
SwipeButton.swift
import UIKit
@IBDesignable class SwipeButton: UIView {
    public var text: String? = nil //ヒントテキスト

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.commInt()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.commInt()
    }

    public convenience init(_ text: String?) {
        self.init()
        self.text = text
        self.commInt()
    }

    private func commInt() {
        self.backgroundColor = backColor

        self.addSubview(bar)
        self.bar.addSubview(textLabel)
        self.addSubview(button)
        self.bringSubviewToFront(button)
    }
4) UIViewのlayoutSubviewsメソットをoverrideして以下の動作を実装する
SwipeButton.swift
    public var isRightToLeft: Bool = true //どの方向に移動するか定義
    public var isEnabled: Bool = true //ユーザが操作できるか定義
    private var startFrame:CGRect! //Buttonが移動する前のFrame情報
    private var turnedFrame:CGRect!//Buttonが移動した後のFrame情報
    @IBInspectable var barHeight: CGFloat = 40.0 //bar部品の高さ

    override func layoutSubviews() {
        super.layoutSubviews()

        let maxWidth: CGFloat = self.frame.width
        let maxHeight: CGFloat = self.frame.height
        if barHeight > maxHeight {
            barHeight = maxHeight
        }
        if barHeight < 10 {
            textLabel.isHidden = true
        }
        self.bar.frame = CGRect(x: 0, y: (maxHeight - barHeight) / 2, width: maxWidth, height: barHeight)
        if self.text != nil,!textLabel.isHidden {
            textLabel.text = self.text
            textLabel.frame = CGRect(origin: .zero, size: bar.frame.size)
        } else {
            textLabel.frame = CGRect.zero
        }
        let leftFrame = CGRect(x: 0, y: 0, width: maxHeight, height: maxHeight)
        let rightFrame  = CGRect(x: (maxWidth - maxHeight), y: 0, width: maxHeight, height: maxHeight)

        if isRightToLeft {
            self.startFrame = rightFrame
            self.turnedFrame = leftFrame
        } else {
            self.startFrame = leftFrame
            self.turnedFrame = rightFrame
        }
        button.frame = startFrame

        if isEnabled {
            button.isUserInteractionEnabled = true
        } else {
            button.isUserInteractionEnabled = false
        }
        self.corner(bar)
        self.corner(button)
        if borderWidth > 0 {
            self.bouder(bar, width: borderWidth, color: borderColor)
        }
5) 上記のcornerメソットとbouderメソットについて、エクステンションして実装しておく
SwipeButton.swift
extension SwipeButton {
    func bouder(_ view: UIView, width: CGFloat, color: UIColor) {
        view.layer.masksToBounds = true
        view.layer.borderColor = color.cgColor
        view.layer.borderWidth = width
    }

    func corner(_ view: UIView, radius: CGFloat = 0) {
        view.layer.masksToBounds = true
        view.layer.cornerRadius = (radius > 0) ? radius : (view.frame.height / 2)
    }
}
6) buttonがSwipeする動作に対して、動画効果のメソットをエクステンションして実装しておく
SwipeButton.swift
    // Swipeした後の部品色について、定義する
    @IBInspectable var swipedFrontColor : UIColor = UIColor.red
    @IBInspectable var swipedGroundColor : UIColor = UIColor.darkGray
    @IBInspectable var swipedTextColor : UIColor = UIColor.systemYellow
    //Swipeした後,表示しようとするテキストを定義
    public var swipedText: String?

extension SwipeButton {
    // 前に進む動画処理
    func swipeToGo() {
        UIView.animate(withDuration: self.duration, animations: {
            self.button.frame = self.turnedFrame
        }){ (completed) in
            self.button.backgroundColor = self.swipedFrontColor
            self.bar.backgroundColor = self.swipedGroundColor
            self.textLabel.textColor = self.swipedTextColor
            if let swipedText = self.swipedText {
                self.textLabel.text = swipedText
            }
        }
    }
    // 元に戻る動画処理
    func swipeToBack() {
        UIView.animate(withDuration: self.duration, animations: {
            self.button.frame = self.startFrame
        }){ (completed) in
            self.button.backgroundColor = self.frontColor
            self.bar.backgroundColor = self.groundColor
            self.textLabel.textColor = self.textColor
            if let text = self.text {
                self.textLabel.text = text
            } else {
                self.textLabel.text = nil
            }
        }
    }
}
7) これからはSwipe移動するbuttonクラスを実装する
SwipeButton.swift
protocol RoundViewDelegate: class {
    // ButtongaタッチされたらDelegateプロトコルで通知するメソットを定義しておく
    func roundViewTouchesEnded() -> Void
}
class RoundView: UIView {
    weak var delegate: RoundViewDelegate?

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.isUserInteractionEnabled = true
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
8) UIViewのタッチイベントを検知するtouchesBegan、touchesMoved、touchesEndedメソットをそれぞれ、overrideして、以下の動作を実装する
SwipeButton.swift
    weak var delegate: RoundViewDelegate? // タッチイベントのDelegate
    public var touchSize: CGSize! // 移動範囲
    private var locationInitialTouch: CGPoint! //最初位置

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else{
            return
        }
        let location = touch.location(in: self)
        print(" Began:(\(location.x), \(location.y))")

        locationInitialTouch = location
    }
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {
            return
        }
        let location = touch.location(in: self)
        if location.x < 0 || location.x > touchSize.width { return }
        if location.y < 0 || location.y > touchSize.height { return }
        print(" Moved:(\(location.x), \(location.y))")
        let f = frame.offsetBy(dx: location.x - locationInitialTouch.x, dy: 0)
        if (f.minX >= 0 && f.maxX <= touchSize.width) {
            frame = f
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        defer {
            delegate?.roundViewTouchesEnded()
        }
        guard let touch = touches.first else{
            return
        }
        let location = touch.location(in: self)
        if location.x < 0 || location.x > touchSize.width {
            return
        }
        if location.y < 0 || location.y > touchSize.height {
            return
        }
        print(" Ended:(\(location.x), \(location.y))")
        let f = frame.offsetBy(dx: location.x - locationInitialTouch.x, dy: 0)
        if (f.minX >= 0 && f.maxX <= touchSize.width) {
            frame = f
        }
    }

9) SwipeButtonクラスがRoundViewDelegateが受けた場合の処理を実装する。
SwipeButton.swift
// MARK: - RoundViewDelegate
extension SwipeButton : RoundViewDelegate{
    func roundViewTouchesEnded() {
        if self.button.center.x > (self.frame.width / 2) {
            if self.isRightToLeft {
                swipeToBack()
            } else {
                swipeToGo()
            }
        } else {
            if self.isRightToLeft {
                swipeToGo()
            } else {
                swipeToBack()
            }
        }
    }
}
10) SwipeButtonのlayoutSubviewsメソットにbuttonの移動範囲touchSizeを指定する。
SwipeButton.swift
  override func layoutSubviews() {
        super.layoutSubviews()

        button.touchSize = self.frame.size
10) 最後、作られたSwipeButton部品を使用して見よう
SwipeButton.swift
class ViewController: UIViewController {
    var swipeButton : SwipeButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        setupSwipeButton()
       }

    func setupSwipeButton() {
        if swipeButton == nil {
            self.swipeButton = SwipeButton(frame: CGRect(x:40, y:200, width: 300,height:50))
            swipeButton.isRightToLeft = true
            swipeButton.text = "すぐ買う"
            swipeButton.swipedText = "購入いたしました"
            self.view.addSubview(self.swipeButton)
        }
    }

Swipe後の動作処理については、この文対象以外で一旦、割愛させていください。

上記内容のソースは以下のURLに格納させて頂きます。
https://github.com/hq7781/SwipeButton/

以上、簡単な説明となりますが、乱文で失礼致します。

iOS、Androidアプリの制作なら、hq7781@gmail.comまで、
法人並みに、信頼且つ満足できる製品を納品いたします

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

SwiftDate の使用方法について (2)

基本の使用方法

1、日時解析(文字列からDate型)

1)デフォルトのフォマットから解析されるバタン:

swiftDateExample.swift
let date = "2018-12-12 10:30:00".toDate()
print("日期:", date!.date)
//実行結果:
//日期: 2018-12-12 10:30:00 +0000

(2)指定されたフォマットから解析されるパタン:

swiftDateExample.swift
let date = "2019-12-13 11:30".toDate("yyyy-MM-dd HH:mm")
print("日期:", date!.date)
//実行結果:
//日期: 2019-12-13 11:30:00 +0000

(3)通常日時フォマット(例え:ISO8601,RSS,Alt RSS,.NET,SQL,HTTP ...)などからされるパタン。
//ISO8601フォマットでの文字列から解析

swiftDateExample.swift
//ISO8601フォマットでの文字列から解析
let date1 = "2019-12-14T11:59:29+02:00".toISODate()
print("日期:", date1!.date)
//実行結果:
//日期: 2019-12-14 09:59:29 +0000

//RSSフォマットでの文字列から解析

swiftDateExample.swift
//RSSフォマットでの文字列から解析
let date2 = "15 Dec 2019 22:20:40 +0100".toRSSDate(alt: true)
print("日期:", date2!.date)
//実行結果:
//日期: 2019-12-15 21:20:40 +0000

2、DataInRegionからDateを生成(Regionはディフォルト)

1)DataInRegionの文字列フォマット、又は時間間隔、日時各コンポネートを設定することで、新しい日時を生成できます。

swiftDateExample.swift
//文字列から生成
let date1 = DateInRegion("2019-12-16 08:00:00")!
print("data1:", date1.date)
//実行結果:
//data1: 2019-12-16 08:00:00 +0000

//時間間隔を指定して生成
let date2 = DateInRegion(seconds: 39940)
let date3 = DateInRegion(milliseconds: 5000)
print("data2:", date2.date)
print("data3:", date3.date)
//実行結果:
//data2: 1970-01-01 11:05:40 +0000
//data3: 1970-01-01 00:00:05 +0000

//日時の各コンポネートを指定して生成(1)
let data4 = DateInRegion(components: {
            $0.year = 2019
            $0.month = 12
            $0.day = 17
            $0.hour = 12
            $0.minute = 0
        })
print("data4:", data4!.date)
//実行結果:
//data4: 2019-12-17 03:00:00 +0000

//日時の各コンポネートを指定して生成(2)
let date5 = DateInRegion(year: 2019, month: 12, day: 18,
                         hour: 13, minute: 30, second: 30)
print("data5:", date5.date)
//実行結果:
//data5: 2019-12-18 13:30:30 +0000

 
(2)Region(Timezone, Calendar & Locale)を指定して日時を生成
上記とほぼ同じですが、指定されたRegionをパラメタとして付与します。

swiftDateExample.swift
//Regionを初期化する
let japan = Region(calendar: Calendars.gregorian, zone: Zones.asiaTokyo, locale: Locales.japanese)
let rome = Region(calendar: Calendars.gregorian, zone: Zones.europeRome, locale: Locales.italian)
let seoul = Region(calendar: Calendars.gregorian, zone: Zones.asiaSeoul, locale: Locales.korean)

//文字列から
let date1 = DateInRegion("2019-08-08 08:00:00", region: japan)!
print("data1:", date1.date)

//从时间间隔创建
let date2 = DateInRegion(seconds: 39940, region: rome)
let date3 = DateInRegion(milliseconds: 5000, region: rome)
print("data2:", date2.date)
print("data3:", date3.date)

//日時の各コンポネートを指定して生成(1)
let data4 = DateInRegion(components: {
            $0.year = 2020
            $0.month = 1
            $0.day = 4
            $0.hour = 12
            $0.minute = 0
         }, region: seoul)
print("data4:", data4!.date)
//日時の各コンポネートを指定して生成(2)
let date5 = DateInRegion(year: 2020, month: 1, day: 5, hour: 23, minute: 30, second: 0, region: seoul)
print("data5:", date5.date)

3、日時取得

SwfitDateを利用することで、ある日時のコンポネートから必要なコンポネート(例え、年月日)等を簡単に取得できます

swiftDateExample.swift
let date = Date()
print("現在日時:", date.toString())
print("年:", date.year)
print("月:", date.month)
print("日:", date.day)
print("時:", date.hour)
print("分:", date.minute)
print("秒:", date.second)
print("最寄り時間:", date.nearestHour)
print("今月の日数:", date.monthDays)
print("今年からの何日目?:", date.dayOfYear)
print("今月名称:", date.monthName(.default))
print("今月名称(略称):", date.monthName(.veryShort))
print("今日第何曜日:", date.weekdayOrdinal)
print("今日の曜日:", date.weekday)
print("当月の週番号:", date.weekOfMonth)
print("当年の週番号:", date.weekOfYear)
print("週番号の対象年:", date.yearForWeekOfYear)
print("今日の曜日名:", date.weekdayName(.default))
print("今日の曜日名(略称):", date.weekdayName(.veryShort))
print("今週最初日は?:", date.firstDayOfWeek)
print("今週最後日は?:", date.lastDayOfWeek)
print("今日は何分期:", date.quarter)
print("現在のregion:", date.region)

//実行結果:
//現在日時: 火 11月 12 12:19:41 +0900 2019
//年: 2019
//月: 11
//日: 12
//時: 12
//分: 10
//秒: 55
//最寄り時間: 12
//今月の日数: 30
//今年からの何日目?: 316
//今月名称: 11月
//今月名称(略称): 11
//今日名称: 第12
//今日第何曜日: 2
//今日の曜日: 3
//当月の週番号: 3
//当年の週番号: 46
//週番号の対象年: 2019
//今日の曜日名: 火曜日
//今日の曜日名(略称): 火
//今週最初日は?: 10
//今週最後日は?: 16
//今日は何分期: 4
//現在のregion: {calendar='gregorian', timezone='Asia/Tokyo', locale='ja'}

4、日時指定フォマット化

(1)toFormat()メソットで指定されたフォマットの文字列を生成します。

swiftDateExample.swift
let date = "2019-12-12 10:30:00".toDate()!
//Zone 変換無し
print("現在时间:", date.toFormat("yyyy-MM-dd HH:mm:ss"))
//香港時間に変換して表示
print("香港时间:", date.convertTo(timezone: Zones.asiaHongKong).toFormat("yyyy-MM-dd HH:mm:ss"))

//実行結果:
//現在时间: 2019-12-12 10:30:00
//香港时间: 2019-12-12 09:30:00

(2)相対的な時間(5分前とか、1時間後等)を簡単に計算し生成します。

swiftDateExample.swift
let r1 = (Date() - 2.years).toRelative(style: RelativeFormatter.defaultStyle()) //2年前
let r2 = (Date() - 10.months).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //10 か月前
let r3 = (Date() - 3.weeks).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //3 週間前
let r4 = (Date() - 5.days).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //5 日前
let r5 = (Date() - 12.hours).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //12 時間前
let r6 = (Date() - 30.minutes).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //30 分前
let r7 = (Date() - 30.seconds).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //今
let r8 = (Date() + 30.seconds).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //今
let r9 = (Date() + 30.minutes).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //30 分後
let r10 = (Date() + 12.hours).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //12 時間後
let r11 = (Date() + 5.days).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //5 日後
let r12 = (Date() + 3.weeks).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //3 週間後
let r13 = (Date() + 10.months).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //10 か月後
let r14 = (Date() + 2.years).toRelative(style: RelativeFormatter.defaultStyle(), locale: Locales.japanese) //2 年後

(3).toClock()メソットを利用することで、TimeIntervalを"時:分:秒"フォマットの文字列で表示できます。

swiftDateExample.swift
let interval: TimeInterval = 2.hours.timeInterval + 30.minutes.timeInterval + 15.seconds.timeInterval
print("カウントダウン:", interval.toClock())

//実行結果:
//カウントダウン: 02:30:15

5、閏年、閏月の判断を簡単にする

swiftDateExample.swift
let date1 = "2019-02-12 10:30:00".toDate()!.date
print(date1.toFormat("yyyy年MM月dd日"), "は閏年ですか:", date1.isLeapYear ? "はい" : "いいえ")
print(date1.toFormat("yyyy年MM月dd日"), "は閏月ですか:", date1.isLeapMonth ? "はい" : "いいえ")

let date2 = "2020-02-12 10:30:00".toDate()!.date
print(date2.toFormat("yyyy年MM月dd日"), "は閏年ですか:", date2.isLeapYear ? "はい" : "いいえ")
        print(date2.toFormat("yyyy年MM月dd日"), "は閏月ですか:", date2.isLeapMonth ? "はい" : "いいえ")

//実行結果:
//2019年02月12日 は閏年ですか: いいえ
//2019年02月12日 は閏月ですか: いいえ
//2020年02月12日 は閏年ですか: はい
//2020年02月12日 は閏月ですか: はい

6、Codableプロトーコルへの対応

swiftDateのDateInRegionとRegionはSwiftのCodableプロトコルをサポートするので、簡単にこれらをencode、decode操作を行うことができます。

无论是 DateInRegion 还是 Region 都是完全支持 Swift 的 Codable 协议,这就意味着我们可以方便安全地对它们进行 encode 和 decode 操作。

swiftDateExample.swift
print("Regionをencode, decodeする:")
let region = Region(calendar: Calendars.gregorian, zone: Zones.asiaTokyo, locale: Locales.japanese)
let encodedJSON = try! JSONEncoder().encode(region)
print("encoded: ", encodedJSON)
let decodedRegion = try! JSONDecoder().decode(Region.self, from: encodedJSON)
print("decoded: ", decodedRegion)
print("\n")

print("DateInRegionをencode, decodeする:")
let date = DateInRegion("2020-01-24T13:20:55", region: region)
let encodedDate = try! JSONEncoder().encode(date)
print("encoded: ", encodedDate)
let decodedDate = try! JSONDecoder().decode(DateInRegion.self, from: encodedDate)
print("decoded: ", decodedDate)
print("\n")

//実行結果:
//Regionをencode, decodeする:
//encoded:  63 bytes
//decoded:  {calendar='gregorian', timezone='Asia/Tokyo', locale='ja'}
//
//DateInRegionをencode, decodeする:
//encoded:  91 bytes
//decoded:  {abs_date='2020-01-24T04:20:55Z', rep_date='2020-01-24T13:20:55+09:00', region=//{calendar='gregorian', timezone='Asia/Tokyo', locale='ja'}

ここまで、SwiftDateの簡単な使用方法について、纏めてみました。
次回はSwiftDateの計算方法や拡張機能について少し説明しようと思います。

iOS、Androidアプリの制作なら、hq7781@gmail.comまで、
法人並みに、信頼且つ満足できる製品を納品いたします

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

SwiftDate の使用方法について (1)

SwiftDateとは

説明:
(1)SwiftDateはSwift言語で開発されたDateライブラリーで、凄く簡単に日時処理が可能になります 。
主な機能:
(2)SwiftDateはほどんとの日時関連機能が揃えて、簡単な日時計算を含め、複雑な業務ロジックの簡単に実現できます。
例え:
• 演算子符の日時加減計算が可能です(例え:curDate + 2.week + 1.hour)
• 比較演算子を対応します(例え <、>、==、<=、>=)
• 簡単に日時の指定部分の取得修正操作ができます(例え、日時の月分のみ修正又は取得したい)
• 通常、又は任意指定されたフォマットで日時出力できます
• .toString()メソットで、色んなフォマットの文字列形式の表示が可能です
• yesterday、tomorrowなど、特別な計算無しで、簡単な方法で取得できます

インストールと初期設定

インストール
SwiftDateはSwift4.xから5まで対応されており、最新版は以下のUrlから取得可能です。
 https://github.com/malcommac/SwiftDate
上記URLから案内する通り、CocoaPods、Carthage、Swift Package Manager等のツールを利用してインストールする方法もありますが、以下ようにソースを直接追加する方法もあります。

ソースを直接追加してインストールする:
1、上記github.comから最新版のソースをダウンロードする。
2、ダウンロードされたソースのSwiftDate.xcodeprojを自分のプロジェクトにマウス操作で引張り込む。
3、プロジェクト -> General -> Embedded Binaries 項目中、iOS 版のSwiftDate.frameworkを追加する。
4、最後、ソースにSwiftDateを利用する部分で、importして宣言する。

但し、Regionの初期設定を行わないと時刻表示が現在地の時刻とずれるので、以下ように初期化処理が必要であります。
例え、日本時間の表示を設定したい場合は

AppDelegate.swift
    let japan = Region(calendar: Calendars.gregorian, zone: Zones.asiaTokyo, locale: Locales.japanese)
    SwiftDate.defaultRegion = japan

次回はSwiftDateの基本使用方法について説明いたします。

iOS、Androidアプリの制作なら、hq7781@gmail.comまで、
法人並みに、信頼且つ満足できる製品を納品いたします

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

Swift ハッシュ関数 SHA-256

ハッシュ関数 SHA-256

Secure Hash Algorithm 256 bit
入力データサイズに関わらず256ビットのハッシュ値を生成。
NIST(National Insitute of Standards and Technology)(アメリカ国立標準技術研究所)で標準化。

コード

Example

import CryptoKit

var hello = "hello"
var data = hello.data(using: .utf8)

print(SHA256.hash(data: data!))

結果

SHA256 digest: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

memo

  • Document
  • 対応:iOS 13+、macOS 10.15+
  • SHA512、SHA384もある
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む