开发者社区> 问答> 正文

快速改变设备方向时不显示浮动动作按钮的视图

我正在尝试创建一个快速的浮动动作按钮。我用我在YouTube上找到的视频制作了一个,尽管有一些缺点,它还是奏效了。另一个问题是视频是印地语的,所以有些地方我不完全理解。https://www.youtube.com/watch?v=xArCnGGzZEE

虽然这是一个很好的视频,但也有一些缺点,我正试图解决,供我自己使用。第一种情况是,当按下浮动按钮时,就会出现模糊视图,但它只适用于肖像方向。我设法解决了这个问题,但另一个问题使我迷失了方向。

因此,浮动操作按钮工作,并出现一个清晰的视图,其中包含几个按钮。问题是,当方向改变时,按钮退出,而我改变方向,按钮就消失了。如果将方向更改为按下浮动操作按钮的方向,则带有按钮的视图将再次出现。这意味着视图正在某个地方,我试图找到它,但是我无法在没有导致错误的约束的情况下找到它。

为了证明我的观点,这就是我的观点。

https://i.stack.imgur.com/eNIKp.png

这就是我按下浮动动作按钮时的样子,而且效果很好。

https://i.stack.imgur.com/kIHEj.png

这就是问题的症结所在。当我改变设备的方向时,我把相机和照片按钮忘了。

https://i.stack.imgur.com/9ECBX.png

如果我改变方向回肖像,相机和照片按钮回来,所以这意味着按钮的位置是移动的视野之外。

https://i.stack.imgur.com/dQNpN.png

这也是奇怪的,因为如果我按下浮动动作按钮,而设备是在景观方向,它工作得很好。

https://i.stack.imgur.com/08Ex7.png

我把方向改为肖像,相机和照片按钮也消失了。我知道它应该还在那里,因为模糊的观点仍然有效。

https://i.stack.imgur.com/6tsru.png

这是按钮的视图。

import Foundation
import UIKit

public typealias CameraButtonAction = (CameraButton) -> Void

open class CameraButton: NSObject {

    //the action the button should perform when tapped
    var action: CameraButtonAction?

    //the button's background color: set default color and selected color
    var backgroundColor: UIColor = UIColor.darkGray {
        willSet {
            floatButton.backgroundColor = newValue
            backgroundColorSelected = newValue
        }
    }

    //the button's background color: set default color
    var backgroundColorSelected: UIColor = UIColor.darkGray

    //indicates if the button is active
    var active: Bool = false


    //an array of items that the button will present
    var items: [CameraButtonItem]? {
        willSet {
            if let item = self.items {
                for abi in item {
                    abi.view.removeFromSuperview()
                }
            }
        }
        didSet {
            placeButtonItems()
            showActive(true)
        }
    }

    //the button that will be presented to the user
    var floatButton: UIButton!

    //view that will hold the placement of the button's actions
    var contentView: UIView!

    //view where the floatbutton will be displayed
    var parentView: UIView!

    //blur effect that will be presented when the button is active
    var blurVisualEffect: UIVisualEffectView!

    //distance between each item action
    let itemOffset = -55

    //the float button's radius
    let floatBtnRadius = 50

    public init(attachedToView view: UIView, items: [CameraButtonItem]?) {
        super.init()

        //creates the float button
        self.parentView = view
        self.items = items
        let bounds = self.parentView.bounds

        self.floatButton = UIButton(type: .custom)
        self.floatButton.layer.cornerRadius = CGFloat(floatBtnRadius / 2)
        self.floatButton.layer.shadowOpacity = 1
        self.floatButton.layer.shadowRadius = 2
        self.floatButton.layer.shadowOffset = CGSize(width: 1, height: 1)
        self.floatButton.layer.shadowColor = UIColor.gray.cgColor

        let cameraImg = UIImage(named: "otherCamera")
        self.floatButton.setImage(cameraImg, for: UIControl.State())
        self.floatButton.backgroundColor = self.backgroundColor
        self.floatButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 8, right: 0)
        self.floatButton.isUserInteractionEnabled = true
        self.floatButton.translatesAutoresizingMaskIntoConstraints = false

        self.floatButton.addTarget(self, action: #selector(CameraButton.buttonTapped(_:)), for: .touchUpInside)
        self.floatButton.addTarget(self, action: #selector(CameraButton.buttonTouchDown(_:)), for: .touchDown)
        self.parentView.addSubview(self.floatButton)


        self.contentView = UIView(frame: bounds)


        self.blurVisualEffect = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
        blurVisualEffect.translatesAutoresizingMaskIntoConstraints = false
        self.blurVisualEffect.frame = self.contentView.frame
        self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        self.blurVisualEffect.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        self.contentView.addSubview(self.blurVisualEffect)
        self.contentView.insertSubview(self.blurVisualEffect, at: 0)
        let tap = UITapGestureRecognizer(target: self, action: #selector(CameraButton.backgroundTapped(_:)))
        self.contentView.addGestureRecognizer(tap)

        self.installConstraints()
    }


    required public init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }



    func setImage(_ image: UIImage?, forState state: UIControl.State) {
        floatButton.setImage(image, for: state)
        floatButton.adjustsImageWhenHighlighted = false
        floatButton.contentEdgeInsets = UIEdgeInsets.zero
    }

    //MARK: - Auto Layout Methods
    //install all the necessary constraints for the button. By the default the button will be placeed at 15pts from the bottom and the 15 pts from the right of its parentView

    func installConstraints() {
        let views: [String: UIView] = ["floatButton":self.floatButton, "parentView":self.parentView]
        let width = NSLayoutConstraint.constraints(withVisualFormat: "H:[floatButton(\(floatBtnRadius))]", options: NSLayoutConstraint.FormatOptions.alignAllCenterX, metrics: nil, views: views)
        let height = NSLayoutConstraint.constraints(withVisualFormat: "V:[floatButton(\(floatBtnRadius))]", options: NSLayoutConstraint.FormatOptions.alignAllCenterX, metrics: nil, views: views)
        self.floatButton.addConstraints(width)
        self.floatButton.addConstraints(height)

        let trailingSpacing = NSLayoutConstraint.constraints(withVisualFormat: "V:[floatButton]-15-|", options: NSLayoutConstraint.FormatOptions.alignAllCenterX, metrics: nil, views: views)
        let bottomSpacing = NSLayoutConstraint.constraints(withVisualFormat: "H:[floatButton]-15-|", options: NSLayoutConstraint.FormatOptions.alignAllCenterX, metrics: nil, views: views)
        self.parentView.addConstraints(trailingSpacing)
        self.parentView.addConstraints(bottomSpacing)


    }


    //MARK: - Button Actions Methods
    @objc func buttonTapped(_ sender: UIControl) {
        animatePressingWithScale(1.0)

        if let unwrappedAction = self.action {
            unwrappedAction(self)
        }
    }

    @objc func buttonTouchDown(_ sender: UIButton) {
        animatePressingWithScale(0.9)
    }

    //MARK: -Gesture Recognizer Methods
    @objc func backgroundTapped(_ gesture: UIGestureRecognizer) {
        if self.active {
            self.toggle()
        }
    }

    //MARK: - Custom methods

    //presents or hides all the actionButtons actions
    func toggleMenu() {
        self.placeButtonItems()
        self.toggle()
    }

    //MARK: Action Button Item Placement
    //defines the posistion of all the actionButton's actions
    func placeButtonItems() {
        if let optionalItems = self.items {
            for item in optionalItems {
                item.view.center = CGPoint(x: self.floatButton.center.x - 83, y: self.floatButton.center.y)
                //item.view.removeFromSuperview()
                self.contentView.addSubview(item.view)
            }
        }
    }


    //MARK: - Float menu Methods
    //presents or hides all the actionButton's actions and changes the active state
    func toggle() {
        //print("First: \(active)")
        self.animateMenu()
        self.showBlur()

        self.active = !self.active
        self.floatButton.backgroundColor = self.active ? backgroundColorSelected : backgroundColor
        self.floatButton.isSelected = self.active
        print("Second: \(active)")
    }

    func animateMenu() {
        UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.1, options: UIView.AnimationOptions.allowAnimatedContent, animations: {
            self.showActive(false)
        }, completion: {completion in
            if self.active == false {
                //self.hideBlur()
            }
        })
    }

    func showActive(_ active: Bool) {
        if self.active == active {
            self.contentView.alpha = 1.0

            if let optionalItems = self.items {
                for (index, item) in optionalItems.enumerated() {
                    let offset = index + 1
                    let translation = self.itemOffset * offset
                    item.view.transform = CGAffineTransform(translationX: 0, y: CGFloat(translation))
                    item.view.alpha = 1
                }
            }
        } else {
            self.contentView.alpha = 0.0
            if let optionalItems = self.items {
                for item in optionalItems {
                item.view.transform = CGAffineTransform(translationX: 0, y: 0)
                item.view.alpha = 0
                }
            }
        }
    }

    func showBlur() {
        self.parentView.insertSubview(self.contentView, belowSubview: self.floatButton)
    }

    func hideBlur() {
        self.contentView.removeFromSuperview()
    }

    //animating the button by pressing, by the default this method just scales the button down when its pressed and returns to its normal size when the button is no longer pressed
    //parameter scale: how much the button should be scaled
    func animatePressingWithScale(_ scale: CGFloat) {
        UIView.animate(withDuration: 0.2, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.1, options: UIView.AnimationOptions.allowAnimatedContent, animations: {
            self.floatButton.transform = CGAffineTransform(scaleX: scale, y: scale)
        }, completion: nil)
    }

}

这是按钮项的视图。

import Foundation
import UIKit

public typealias CameraButtonItemAction = (CameraButtonItem) -> (Void)


open class CameraButtonItem: NSObject {

    //the action the item should perform when tapped
    open var action: CameraButtonItemAction?

    //Description of the item's action
    open var text: String {
        get {
            return self.label.text!
        }
        set {
            self.label.text = newValue
        }
    }

    //view that will hold the item's button and label
    var view: UIView!

    //label that contain the item's text
    var label: UILabel!

    //main button that will perform the defined action
    var button: UIButton!

    //image used by the button
    var image: UIImage!

    //size needed for the view property present the item's content
    let viewSize = CGSize(width: 200, height: 35)

    //button's size by default the button is 35x35
    let buttonSize = CGSize(width: 35, height: 35)

    var labelBackground: UIView!
    let backgroundInset = CGSize(width: 10, height: 10)

    public init(title optionalTitle: String?, image: UIImage?) {
        super.init()
        //so when the button is pressed a view will appear with buttons and labels that can be pressed. The view has no background color.
        self.view = UIView(frame: CGRect(origin: CGPoint.zero, size: self.viewSize))
        self.view.alpha = 0
        self.view.isUserInteractionEnabled = true
        //self.view.backgroundColor = UIColor.purple


        //this creates the button that we can press
        self.button = UIButton(type: .custom)
        self.button.frame = CGRect(origin: CGPoint(x: self.viewSize.width - self.buttonSize.width, y: 0), size: buttonSize)
        self.button.layer.shadowOpacity = 1
        self.button.layer.shadowRadius = 2
        self.button.layer.shadowOffset = CGSize(width: 1, height: 1)
        self.button.layer.shadowColor = UIColor.black.cgColor
        self.button.addTarget(self, action: #selector(CameraButtonItem.buttonPressed(_:)), for: .touchUpInside)

        if let unwrappedImage = image {
            self.button.setImage(unwrappedImage, for: UIControl.State())
        }

        if let text = optionalTitle, text.trimmingCharacters(in: CharacterSet.whitespaces).isEmpty == false {
            self.label = UILabel()
            self.label.font = UIFont(name: "HelveticaNeue-Medium", size: 13)
            self.label.textColor = UIColor.black
            self.label.textAlignment = .center
            self.label.text = text
            self.label.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(CameraButtonItem.labelTapped(_:))))
            self.label.sizeToFit()

            self.labelBackground = UIView()
            self.labelBackground.frame = self.label.frame
            self.labelBackground.backgroundColor = UIColor.white
            self.labelBackground.layer.cornerRadius = 5
            self.labelBackground.layer.shadowOpacity = 0.8
            self.labelBackground.layer.shadowOffset = CGSize(width: 0, height: 1)
            self.labelBackground.layer.shadowRadius = 0.2
            self.labelBackground.layer.shadowColor = UIColor.lightGray.cgColor

            //Adjust the label's background inset
            self.labelBackground.frame.size.width = self.label.frame.size.width + backgroundInset.width
            self.labelBackground.frame.size.height = self.label.frame.size.height + backgroundInset.height
            self.label.frame.origin.x = self.label.frame.origin.x + backgroundInset.width / 2
            self.label.frame.origin.y = self.label.frame.origin.y + backgroundInset.height / 2

            //adjust the label's background position
                //distance between the button and the label
            self.labelBackground.frame.origin.x = CGFloat(130 - self.label.frame.size.width)
            self.labelBackground.center.y = self.view.center.y
            self.labelBackground.addSubview(self.label)

            //Add Tap Gesture Recognizer
            let tap = UITapGestureRecognizer(target: self, action: #selector(CameraButtonItem.labelTapped(_:)))
            self.view.addGestureRecognizer(tap)

            self.view.addSubview(self.labelBackground)
        }
        self.view.addSubview(self.button)
    }


    //MARK: -Button Action Methods
    @objc func buttonPressed(_ sender: UIButton) {
        if let unwrappedAction = self.action {
            unwrappedAction(self)
        }
    }

    //MARK: - Gesture Recognizer Methods
    @objc func labelTapped(_ gesture: UIGestureRecognizer) {
        if let unwrappedAction = self.action {
            unwrappedAction(self)
        }
    }


}

这是我在集合视图中设置的视图控制器

import UIKit

extension ViewController: UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 100, height: 150)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
    }
}


extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! TestingCollectionViewCell
        cell.backgroundColor = .white
        let img = UIImage(named: self.items[indexPath.row])
        cell.imageView.image = img
        cell.imageName.text = "\(self.items[indexPath.row])"
        return cell
    }


    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("\(items[indexPath.row])")
        self.presentInfoView(withInfo: items[indexPath.row])
    }
}

class ViewController: UIViewController, BlurDelegate {

    var actionButton: CameraButton!




    func removeBlurView() {
        for subview in view.subviews {
            if subview.isKind(of: UIVisualEffectView.self) {
                subview.removeFromSuperview()
                self.infoView.removeFromSuperview()
            }
        }
    }


    fileprivate var items: [String] = [
        "photo1",
        "photo2",
        "photo3",
        "photo4",
        "photo5",
        "photo6",
        "photo7",
        "photo8",
        "photo9",
        "photo10",
        "photo11",
        "photo12",
        "photo13",
        "photo14",
        "photo15",
        "photo16",
        "photo17",
        "photo18",
        "photo19",
        "photo20",
        "photo21",
        "photo22",
        "photo23",
        "photo24"
    ]

    override func viewDidLoad() {
        super.viewDidLoad()

        let collection = UICollectionView(frame: view.frame, collectionViewLayout: UICollectionViewFlowLayout())
                //allows us to use auto layout constraints
        collection.translatesAutoresizingMaskIntoConstraints = false
        collection.backgroundColor = .black
        view.addSubview(collection)
        collection.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        collection.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        collection.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        collection.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true

        collection.dataSource = self
        collection.delegate = self

        collection.register(TestingCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
        self.navigationItem.title = "Testing"
        setUpButton()

    }

    func setUpButton() {
        let cameraBtn = UIImage(named: "CameraBtn")
        let photoBtn = UIImage(named: "PhotoBtn")
        let cameraRound = UIImage(named: "otherCamera")
        let camera = CameraButtonItem(title: "Camera", image: cameraBtn)
        let photo = CameraButtonItem(title: "Photo", image: photoBtn)
        camera.action = { item in
            print(item)
            print("Camera Btn Pressed")
        }
        photo.action = { item in
            print(item)
            print("Photo Btn Pressed")
        }

        actionButton = CameraButton(attachedToView: self.view, items: [camera, photo])
        actionButton.setImage(cameraRound, forState: UIControl.State())
        actionButton.backgroundColor = .green
        actionButton.action = { button in button.toggleMenu()
            //self.setBlurView()
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        var touch: UITouch? = touches.first
        if touch?.view != infoView {
            dismissView()

        }
    }




    func dismissView() {

        //dismiss(animated: true, completion: nil)
        removeBlurView()

    }

    func setBlurView() {
        let blurView = UIVisualEffectView()
        blurView.frame = view.frame
        blurView.effect = UIBlurEffect(style: .regular)
        blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(blurView)
    }

    func presentInfoView(withInfo info: String) {
        setBlurView()
        view.addSubview(infoView)
        //infoView.addView()
        let img = UIImage(named: info)
        infoView.imageView.image = img
        infoView.nameLbl.text = info


        infoView.backgroundColor = .white
        infoView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        infoView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8).isActive = true
        //infoView.widthAnchor.constraint(equalToConstant: view.frame.width - 64).isActive = true
        infoView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.8).isActive = true
        //infoView.heightAnchor.constraint(equalToConstant: view.frame.height - 64).isActive = true
        infoView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -44).isActive = true
        infoView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)

        infoView.alpha = 0

        UIView.animate(withDuration: 0.5) {
            self.infoView.alpha = 1
            self.infoView.transform = .identity
        }
    }

}

我试图为视图和浮动操作按钮添加一个约束,但它会导致整个事件崩溃。我还尝试添加一个函数,在设备方向发生变化时删除当前的约束,并为特定的方向添加一个新的约束,但没有真正的区别。

如果我能提供更多的信息,请询问。非常感谢

展开
收起
游客5akardh5cojhg 2019-12-12 14:35:11 552 0
0 条回答
写回答
取消 提交回答
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
用计算和数据去改变整个世界 立即下载
低代码开发师(初级)实战教程 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载