Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to add alignment on button styles? #191

Closed
jhochenbaum opened this issue Dec 6, 2017 · 13 comments
Closed

Possible to add alignment on button styles? #191

jhochenbaum opened this issue Dec 6, 2017 · 13 comments
Labels

Comments

@jhochenbaum
Copy link

jhochenbaum commented Dec 6, 2017

Report

Environment

Please provide information on your development environment, so we can build with the same scenario.

  • Xcode version (e.g. 9.1): 8.3.2
  • PopupDialog version (e.g. 0.5.0): 0.6
  • Minimum deployment target (e.g. 9.0): 9.0
  • Language (Objective-C / Swift): Swift
  • In case of Swift - Version (e.g. 4): 4

Dependency management

If you are not using any dependency managers, you can remove this section.

  • Dependency manager (e.g. CocoaPods): CocoaPods
  • Version (e.g. 1.3.1): ℹ

What did you do?

I tried fiddling with button.contentHorizontalAlignment and button.contentEdgeInserts in order to make the buttons right aligned, similar to how Google Material aligns "flat buttons" in Material alerts and dialogues:

screen shot 2017-12-05 at 7 53 52 pm

What did you expect to happen?

Buttons to align to the right of the view

What happened instead?

Buttons are always centered and take over the full width of the view, presumably because there is some auto-layout config going on.

Thoughts? Love this library for its ease of use, and ability to add images, but would be really nice if it was just a little more flexible in this way.

@mwfire
Copy link
Member

mwfire commented Dec 6, 2017

Hey @jhochenbaum, the dialog buttons are subclasses of UIButton, so you can set alignment the same way you would do it with UIButtons. That is

yourButton.contentHorizontalAlignment = .right
yourButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 20)

Full width, however, is the default at the moment. That would be a great idea for a Pull Request, though ;)

What do you think?

@jhochenbaum
Copy link
Author

Thanks for the reply @mwfire

Indeed I had tried to do something similar for a while tonight, but with two buttons next to each other, it was really difficult to find good values for each button's contentEdgeInsets where they were positioned correctly and their clickable regions made sense. For some reason I just couldn't get it right, I think because even when moving them around. they try to fill the whole width. Maybe I was setting contentEdgeInsets incorrectly though...

The best solution I came up with (without digging into the library itself) is a total hack, but functionality worked nice. This was to add a third invisible dummy button to the left, and set dummyButton.isUserInteractionEnabled = false; Super hacky but the result was nice (good radius/active region for the actual clickable buttons, and nothing to the empty space on the left)

screen shot 2017-12-05 at 10 39 46 pm

The real solution I guess would indeed be to do this inside the library and change the layout constraint I guess so that it wouldn't be forced to try and auto-fill the entire width, or somehow figure out how to get contentEdgeInsets set correctly on the two buttons!

@ETmanwenhan
Copy link

@jhochenbaum I have this need, too. Do you already have a good solution?

@ETmanwenhan
Copy link

@mwfire I'll do it your way. But the effect is not ideal.

cf0287ef-b25a-456d-9303-fde5c9c3d795

@jhochenbaum
Copy link
Author

@ETmanwenhan Yes that is what I ran into as well. I ended up hacking it with a third invisible and non-interactive button as mentioned, but a modification to the library that removed or parameterized the auto full-width layout would be a better long-term solution.

@ETmanwenhan
Copy link

@jhochenbaum
How do you solve the extra space?

 // The container stack view for buttons
    internal lazy var buttonStackView: UIStackView = {
        let buttonStackView = UIStackView()
        buttonStackView.translatesAutoresizingMaskIntoConstraints = false
        buttonStackView.distribution = **.fillProportionally**
        buttonStackView.spacing = 0
        return buttonStackView
    }()
buttonOne.contentHorizontalAlignment = .right
        buttonOne.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        
        buttonTwo.contentHorizontalAlignment = .right
        buttonTwo.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 10)

@ETmanwenhan
Copy link

@jhochenbaum @mwfire
daf6b5a2-5e22-4dfa-9fb9-6edfdf58664b

@jhochenbaum
Copy link
Author

jhochenbaum commented Dec 22, 2017

` // Create buttons

        // Non-interactive dummy button to get around auto-layout
        // styling/position limitations with PopupDialog
        let dummyButton = DefaultButton(title: "") {}
        dummyButton.isUserInteractionEnabled = false;
        
        let cancelButton = CancelButton(title: "NOT NOW") {}
        
        let acceptButton = DefaultButton(title: "YES PLEASE!") {}
        
        cancelButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 16, bottom:0, right: 0)
        acceptButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16)
        // Add buttons to dialog
        popup.addButtons([dummyButton, cancelButton, acceptButton])`

@jhochenbaum
Copy link
Author

Again not my preferred route but in the interest of time I moved on for now ;)

@jhochenbaum
Copy link
Author

Looks like you're on to the proper solution though!

@ETmanwenhan
Copy link

@jhochenbaum
How to control the width of the button? Too wide!

@ETmanwenhan
Copy link

@jhochenbaum Here's my solution:

 let customVC  = NickAlertView()
        let alertView = YYPopupDialog(viewController: customVC, title: "标题", msg: "内容", transitionStyle: .zoomIn, completion: nil)
        let buttonOne = YYCancelButton(title: "Cancel") {
            Loger.log(msg: "canceled")
        }
        let buttonTwo = YYDefaultButton(title: "Ok") {
            Loger.log(msg: "ok:\(customVC.textField.text ?? "")")
        }
        alertView.addButtons([buttonOne, buttonTwo])
        self.present(alertView, animated: true, completion: nil)
//
//  BaseAlertView.swift
//  yiyue
//
//  Created by ChenWenHan on 2017/12/19.
//  Copyright © 2017年 YiBan. All rights reserved.
//

import UIKit

class YYPopupDialog: UIViewController {
    
    /// First init flag
    fileprivate var initialized = false
    
    /// The custom transition presentation manager
    fileprivate var presentationManager: PresentationManager!
    
    /// Interactor class for pan gesture dismissal
    fileprivate lazy var interactor = InteractiveTransition()
    
    /// Width for iPad displays
    fileprivate let preferredWidth: CGFloat
    
    /// The completion handler
    fileprivate var completion: (() -> Void)?
    
    /// The content view of the popup dialog
    public var viewController: UIViewController
    
    weak var popupContainerView: UIView!
    
    /// The set of buttons
    fileprivate var buttons = [PopupDialogButton]()
    
    // MARK: - View life cycle
    public override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        guard !initialized else { return }
        appendButtons()
        setupLayout()
        initialized = true
    }

    public init(
        viewController: UIViewController,
        title: String?,
        msg: String?,
        transitionStyle: PopupDialogTransitionStyle = .zoomIn,
        preferredWidth: CGFloat = 330,
        gestureDismissal: Bool = true,
        completion: (() -> Void)? = nil) {
        
        self.completion = completion
        self.viewController = viewController
        self.preferredWidth = preferredWidth
        super.init(nibName: nil, bundle: nil)
        
        // Init the presentation manager
        presentationManager = PresentationManager(transitionStyle: transitionStyle, interactor: interactor)
        
        // Assign the interactor view controller
        interactor.viewController = self
        
        // Define presentation styles
        transitioningDelegate = presentationManager
        modalPresentationStyle = .custom
        
        // StatusBar setup
        //modalPresentationCapturesStatusBarAppearance = true
        
        // Add our custom view to the container
        addChildViewController(viewController)
        view.addSubview(viewController.view)
        viewController.didMove(toParentViewController: self)
        popupContainerView = self.viewController.view
 
        
        // Allow for dialog dismissal on background tap and dialog pan gesture
        if gestureDismissal {
            let panRecognizer = UIPanGestureRecognizer(target: interactor, action: #selector(InteractiveTransition.handlePan))
            popupContainerView.addGestureRecognizer(panRecognizer)
            let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
            tapRecognizer.cancelsTouchesInView = false
            panRecognizer.cancelsTouchesInView = false
            view.addGestureRecognizer(tapRecognizer)
        }
        
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    func setupLayout() {
        
        
        popupContainerView.snp.updateConstraints({ (make) in
            make.centerX.equalTo(self.view.snp.centerX)
            make.centerY.equalTo(self.view.snp.centerY)
        })
        
        
        var suffixBtn: UIButton? = nil
        for (index, button) in buttons.enumerated().reversed() {
            
            button.contentHorizontalAlignment = .right
            button.titleLabel?.adjustsFontSizeToFitWidth = true //自动调整文字宽度
            if (index == 0) {
                button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 0)
            } else {
                button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
            }
            
            button.snp.makeConstraints { (make) in

                if let btn = suffixBtn {
                    make.right.equalTo(btn.snp.left)
                } else {
                    make.right.equalTo(popupContainerView.snp.right).offset(-24)
                }
                make.height.equalTo(30)
                make.bottom.equalTo(popupContainerView.snp.bottom).offset(-12)
            }
            suffixBtn = button
        }
    }
    
    // MARK: - Dismissal related
    
    @objc fileprivate func handleTap(_ sender: UITapGestureRecognizer) {
        
        // Make sure it's not a tap on the dialog but the background
        let point = sender.location(in: popupContainerView)
        guard !popupContainerView.point(inside: point, with: nil) else { return }
        dismiss()
    }
    
    /*!
     Dismisses the popup dialog
     */
    public func dismiss(_ completion: (() -> Void)? = nil) {
        self.dismiss(animated: true) {
            completion?()
        }
    }

    deinit {
        completion?()
        completion = nil
        Loger.log(msg: "销毁")
    }
    
    
    // MARK: - Button 相关
    
    /*!
     Appends the buttons added to the popup dialog
     to the placeholder stack view
     */
    fileprivate func appendButtons() {
        
        for (_, button) in buttons.enumerated() {
            //button.needsLeftSeparator = index > 0
            button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
            popupContainerView.addSubview(button)
        }
    }
    
    /*!
     Adds a single PopupDialogButton to the Popup dialog
     - parameter button: A PopupDialogButton instance
     */
    public func addButton(_ button: PopupDialogButton) {
        buttons.append(button)
    }
    
    /*!
     Adds an array of PopupDialogButtons to the Popup dialog
     - parameter buttons: A list of PopupDialogButton instances
     */
    public func addButtons(_ buttons: [PopupDialogButton]) {
        self.buttons += buttons
    }
    
    /// Calls the action closure of the button instance tapped
    @objc fileprivate func buttonTapped(_ button: PopupDialogButton) {
        if button.dismissOnTap {
            dismiss({ button.buttonAction?() })
        } else {
            button.buttonAction?()
        }
    }
    
    /*!
     Simulates a button tap for the given index
     Makes testing a breeze
     - parameter index: The index of the button to tap
     */
    public func tapButtonWithIndex(_ index: Int) {
        let button = buttons[index]
        button.buttonAction?()
    }

}
//
//  NickAlertView.swift
//  yiyue
//
//  Created by ChenWenHan on 2017/12/20.
//  Copyright © 2017年 YiBan. All rights reserved.
//

import UIKit

class NickAlertView: UIViewController {
    
    lazy var popupContainerView: UIView = {
        let view = UIView(frame: kScreen)
        view.clipsToBounds = true
        view.layer.cornerRadius = 4
        view.backgroundColor = UIColor.white
        return view
    }()
    
    lazy var titleLable : UILabel = {
        
        let label = UILabel()
        label.text = "输入昵称"
        label.textColor = UIColor.black
        label.font = UIFont.boldSystemFont(ofSize: 16)
        return label
    }()
    
    
    lazy var textField: UITextField = {
        
        var textField = UITextField()
        textField.placeholder = "8个字以内"
        textField.clearButtonMode = .always
        textField.font = UIFont.boldSystemFont(ofSize: 14)
        return textField
    }()
    
    lazy var separator: UIView = {
        
        var view = UIView()
       view.backgroundColor = ColorGray5
        return view
    }()
    
    // MARK: - View life cycle
    
    override func viewDidLayoutSubviews() {
        self.setupLayout()
        super.viewDidLayoutSubviews()
        
    }
    
    override func loadView() {
        super.loadView()
        
        view = popupContainerView
        
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
        //view.addSubview(popupContainerView)
        popupContainerView.addSubview(titleLable)
        popupContainerView.addSubview(textField)
        popupContainerView.addSubview(separator)
        
        
    }
    

    func setupLayout() {
        
        popupContainerView.snp.makeConstraints { (make) in
            
            make.width.equalTo(330)
            make.height.equalTo(182)
            make.centerX.equalTo(self.view.snp.centerX)
            make.centerY.equalTo(self.view.snp.centerY)
        }
        
        titleLable.snp.makeConstraints { (make) in
            
            make.top.equalTo(28)
            make.left.equalTo(popupContainerView.snp.left).offset(24)
        }
        
        textField.snp.makeConstraints { (make) in
            
            make.top.equalTo(titleLable.snp.bottom).offset(32)
            make.left.equalTo(popupContainerView.snp.left).offset(24)
            make.right.equalTo(popupContainerView.snp.right).offset(-24)
            make.height.equalTo(30);
        }
        
        separator.snp.makeConstraints { (make) in
            
            make.left.equalTo(textField.snp.left)
            make.right.equalTo(textField.snp.right)
            make.height.equalTo(0.5);
            make.bottom.equalTo(textField.snp.bottom);
        }
    }
    
    deinit {
        Loger.log(msg: "销毁")
    }

}

98063595-d4ba-4f3e-b9d0-7f4ea16fdd10

@stale
Copy link

stale bot commented Jan 21, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jan 21, 2018
@stale stale bot closed this as completed Jan 28, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants