我正在尝试创建一个快速的浮动动作按钮。我用我在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
}
}
}
我试图为视图和浮动操作按钮添加一个约束,但它会导致整个事件崩溃。我还尝试添加一个函数,在设备方向发生变化时删除当前的约束,并为特定的方向添加一个新的约束,但没有真正的区别。
如果我能提供更多的信息,请询问。非常感谢
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。