make pop up view disappear - ios

I have button, when I click that button, a view pops up.
testingButton.addTarget(self, action: #selector(popupTable), for: .touchUpInside)
#objc func popupTable(){
self.opaqueView = self.setUpPopView()
mainView.addSubview(opaqueView)
print("button clicked")
}
if the view is present, I want to click on the button again and make the view disappear.
if tinyView.isHidden == false {
tinyView.isHidden = false
self.testingButton.addTarget(self, action: #selector(removePopUp), for: .touchUpInside)
}else{
tinyView.isHidden = true
mainView.addSubview(tinyView)
}
Which it does but when I click on the button a third time (pop up view is not present) i want the pop up view to appear again but it doesn't.
show pop up
func setUpPopView () -> UIView {
tinyView.backgroundColor = UIColor(red:0.99, green:0.99, blue:0.99, alpha:1.0)
tinyView.layer.cornerRadius = 3
tinyView.layer.masksToBounds = false
tinyView.layer.shadowColor = UIColor.black.withAlphaComponent(0.4).cgColor
tinyView.layer.shadowOffset = CGSize(width: 0, height: 0)
tinyView.layer.shadowOpacity = 0.9
let post: UIButton = UIButton(frame: CGRect(x: 5, y: 10, width: 150, height: 50))
post.backgroundColor = UIColor.clear
post.setTitleColor(UIColor.black, for:UIControlState.normal)
post.setTitle("All Post", for: .normal)
post.contentHorizontalAlignment = .left
post.addTarget(self, action: #selector(removePopUp), for: .touchUpInside)
tinyView.addSubview(post)
}
remove pop up
#objc func removePopUp(_ sender: AnyObject){
self.tinyView.removeFromSuperview()
}

You should use one action only and check the visibility of the pop up view in the action. According to the visibility of the view you can then show or hide the pop up.
Like this:
#objc func popupAction() {
If self.popUpView.isHidden {
// Pop up view is hidden, so show the pop up view again
} else {
// Pop up view is visible, so hide the pop up view
}
}
Also change this:
if tinyView.isHidden == false
{
tinyView.isHidden = false
self.testingButton.addTarget(self, action: #selector(removePopUp), for: .touchUpInside)
}else{
tinyView.isHidden = true
mainView.addSubview(tinyView)
}
With this:
if tinyView.isHidden == false
{
tinyView.isHidden = true
tinyView.removeFromSuperview()
}else{
tinyView.isHidden = false
mainView.addSubview(tinyView)
}

You should not be calling removeFromSuperview. You should not be saying if. It all just adds unnecessary complications.
If your goal is to show and hide a view, just show it and hide it: toggle its hiddenness, which is a one-liner:
tinyView.isHidden = !tinyView.isHidden
That way, if it is invisible, it becomes visible, and if it is visible, it becomes invisible. In Swift 4.2, it's even simpler:
tinyView.isHidden.toggle()
That's all! You don't need know whether it's already hidden, you don't need to remove it from the superview. No if, no nothing. You just invert its hiddenness each time you want to hide or show it.

Related

Hiding UIButton(which added programatically) once view is hidden

Goal:
Hide a UIButton(w/ image) once a view is hidden.
I have a layout whereby the map view can be hidden when user taps(UITapGestureRecognizer) on the screen. When this happen, I would like to hide the "follow user button" triangle. Currently I am not able to do it.
What I've tried: (from multiple google/SO posts)
1)
followUserButton.removeFromSuperview()
followUserButton.widthAnchor.constraint(equalToConstant: 150).isActive = true
followUserButton.heightAnchor.constraint(equalToConstant: 150).isActive = true
followUserButton.setImage(image:nil for: .normal)
the last one I tried is basically just making the image black in color (to blend into the background). This does look like a success, but (see gif image), for some reason, the first click, will still show the button (very light black/grey - in the bottom middle of image). Click again, the map view comes on, then click again and it finally disappears
followUserButton.tintColor = .black
followUserButton.isHidden = true
this is how I'm adding my button programatically
var followUserImage: UIImage!
var followUserButton: UIButton!
override func viewDidLoad() {
setupFollowUserButton()
}
func setupFollowUserButton() {
addFollowUserButton()
self.view.addSubview(followUserButton)
constraintFollowUserButton()
}
func hideFollowUserButton() {
if vcTrainMapView.isHidden {
if followUserButton != nil {
// followUserButton.removeFromSuperview()
// followUserButton.tintColor = .black
followUserButton.isHidden = true
}
} else if followUserButton != nil {
followUserButton.tintColor = .lightGray
}
}
func addFollowUserButton() {
followUserButton = UIButton(type: UIButton.ButtonType.custom)
followUserImage = UIImage(named: "follow_user_high")
followUserButton.setImage(followUserImage, for:.selected)
followUserImage = (UIImage(named: "follow_user"))
followUserButton.setImage(followUserImage, for: .normal)
followUserButton.tintColor = .lightGray
followUserButton.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)
}
#objc private func buttonAction(_ sender: UIButton) {
self.followUserStatus = !self.followUserStatus
sender.isSelected.toggle()
}
func constraintFollowUserButton() {
followUserButton.translatesAutoresizingMaskIntoConstraints = false
followUserButton.bottomAnchor.constraint(equalTo: vcTrainMapView.bottomAnchor, constant: -10).isActive = true
followUserButton.leadingAnchor.constraint(equalTo: vcTrainMapView.leadingAnchor, constant: 10).isActive = true
followUserButton.widthAnchor.constraint(equalToConstant: 50).isActive = true
followUserButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
}
this is what I've achieved w/ #3 above. (the button is very light in the gif)
If you're going to be hiding and showing a button at the same time as a detail view (your map view), and you're displaying the button so that it looks like it's on that view, you could just add the button directly to that view rather than the view controller main view.
You can, of course, still control the action of the button from the view controller, but if it's added to the map view then the button will be hidden when the map view is hidden.

why does a custom button which added by code in UITabBarController.viewDidLoad doesn't response the selector

I add a custom button to the tabBar in my MyViewController.viewDidLoad(subclass of UITabBarController)
But I find it doesn't response the selector.
If I delay one second to add button(in DispatchQueue.main.asyncAfter closure) ,it works OK.
I think it's not the right way to resolve it.
func addButton() {
let button = UIButton(type: UIButton.ButtonType.custom)
button.bounds = CGRect(x:0,y:0,width:30,height:30);
button.backgroundColor = UIColor.red
button.center = CGPoint(x:self.tabBar.frame.size.width/2, y:self.tabBar.frame.size.height/2 - 20);
button.addTarget(self, action: #selector(click(button:)), for: UIControl.Event.touchUpInside)
tabBar.addSubview(button)
}
You have added button to UITabBar of UITabBarController as half of part of the button would appear above the Tabbar and half of below the Tabbar as per frame.
So I guess you will not get click on part of that button which is out of Tabbar(above Tabbar) would not get touch. I you will make button little big OR try to click with arrow in simulator, you will get idea.
If you need to have button at bottom but slightly upper, then please create custom Tabbar to achieve design like this. Or else you can add that button into UITabBarController’s view instead of Tabbar.
class MyTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.addButton()
}
func addButton() {
let button = UIButton(type: UIButton.ButtonType.custom)
button.bounds = CGRect(x:0,y:0,width:50,height:50); //1
button.backgroundColor = UIColor.purple
button.center = CGPoint(x:self.tabBar.frame.size.width/2, y:self.tabBar.frame.size.height/2 - 50 + self.tabBar.frame.origin.y); //2
button.addTarget(self, action: #selector(click(button:)), for: UIControl.Event.touchUpInside)
button.layer.cornerRadius = button.frame.size.height/2
button.layer.masksToBounds = false
button.layer.shadowColor = UIColor.black.withAlphaComponent(0.5).cgColor
button.layer.shadowRadius = 5.0
button.layer.shadowOffset = CGSize(width: 0.0, height: 5.0)
button.layer.shadowOpacity = 0.5
//tabBar.addSubview(button) //3
self.view.addSubview(button). //4
}
#objc func click(button: UIButton) {
print("Button get clicked")
}
}
I have marked four things with commented by numbers at the end of lines, that you can make to your code and try.

Button doesn’t work properly after subclassing view controller to base controller

I am making a simple app, which for now has 3 pages, and I wanted to have a base view controller to all my view controllers. But my button on the first page, which was working perfectly, that, when clicked, goes to the second page, doesn't work properly anymore, meaning, the button opens up a blank page and not the second page. But when I remove the subclass from the other view controllers, the button works perfectly. BTW I'm creating this app 100% programmatically. I know that I haven't provided the code or any screenshots of my code, but I hope you can help me out! Thanks! :)
// Setup the login button
func setupLoginButton() {
loginButton.backgroundColor = UIColor.clear
loginButton.setTitle("Login", for: .normal)
loginButton.titleLabel?.font = UIFont(name: "Avenir-Heavy", size: 25)
loginButton.setTitleColor(baseColor, for: .normal)
loginButton.layer.borderWidth = 1
loginButton.layer.borderColor = baseColor.cgColor
loginButton.layer.cornerRadius = 25
// Make it go to the main screen when pressed
loginButton.addTarget(self, action: #selector(loginButtonPressed), for: .touchUpInside)
view.addSubview(loginButton)
addLoginButtonConstraints()
}
// Add the constraints to the login button
func addLoginButtonConstraints() {
loginButton.translatesAutoresizingMaskIntoConstraints = false
loginButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
loginButton.widthAnchor.constraint(equalToConstant: 335).isActive = true
loginButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
loginButton.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -5).isActive = true
}
// When login button is pressed
#objc func loginButtonPressed() {
let mainPage = MainScreen()
present(mainPage, animated: true, completion: nil)
}
So here, When I click on the login button, it should go to the mainPage, but it just opens up a blank page.
Here is the mainPage
import UIKit
class MainScreen: BaseAndExtensions {
override func viewDidLoad() {
super.viewDidLoad()
}
}
BaseAndExtensions is the base view controller.

cosmicmind material swift MenuView not closing

I am using cosmicmind material swift library and am following the examples code to try to get the FAB MenuView working.
I have copied the code and added the buttons i want, to test i am just testing with 2 buttons. The problem I am facing is with the handleMenu function:
/// Handle the menuView touch event.
internal func handleMenu() {
if menuView.menu.opened {
menuView.close()
(menuView.menu.views?.first as? MaterialButton)?.animate(MaterialAnimation.rotate(rotation: 0))
} else {
menuView.menu.open() { (v: UIView) in
(v as? MaterialButton)?.pulse()
}
(menuView.menu.views?.first as? MaterialButton)?.animate(MaterialAnimation.rotate(rotation: 0.125))
}
}
The full code for this UINavigationController:
import UIKit
import Material
class MyTeeUpsController: UINavigationController {
/// MenuView reference.
private lazy var menuView: MenuView = MenuView()
/// Default spacing size
let spacing: CGFloat = 16
/// Diameter for FabButtons.
let diameter: CGFloat = 56
/// Handle the menuView touch event.
internal func handleMenu() {
if menuView.menu.opened {
menuView.close()
(menuView.menu.views?.first as? MaterialButton)?.animate(MaterialAnimation.rotate(rotation: 0))
} else {
menuView.menu.open() { (v: UIView) in
(v as? MaterialButton)?.pulse()
}
(menuView.menu.views?.first as? MaterialButton)?.animate(MaterialAnimation.rotate(rotation: 0.125))
}
}
/// Handle the menuView touch event.
internal func handleButton(button: UIButton) {
print("Hit Button \(button)")
}
private func prepareMenuView() {
//let w: CGFloat = 52
var img:UIImage? = MaterialIcon.cm.add?.imageWithRenderingMode(.AlwaysTemplate)
let button1: FabButton = FabButton()//frame: CGRectMake((view.bounds.width - w)-10, 550,w,w))
button1.setImage(img, forState: .Normal)
button1.setImage(img, forState: .Highlighted)
button1.pulseColor = MaterialColor.blue.accent3
button1.backgroundColor = MaterialColor.blueGrey.lighten1
button1.borderColor = MaterialColor.blue.accent3
button1.borderWidth = 1
button1.addTarget(self, action: #selector(handleMenu), forControlEvents: .TouchUpInside)
menuView.addSubview(button1)
img = UIImage(named: "filing_cabinet")?.imageWithRenderingMode(.AlwaysTemplate)
let button2:FabButton = FabButton()
button2.depth = .None
button2.setImage(img, forState: .Normal)
button2.setImage(img, forState: .Highlighted)
button2.pulseColor = MaterialColor.blue.accent3
button2.borderColor = MaterialColor.blue.accent3
button2.borderWidth = 1
button2.backgroundColor = MaterialColor.blueGrey.lighten1
button2.addTarget(self, action: #selector(handleButton), forControlEvents: .TouchUpInside)
menuView.addSubview(button2)
menuView.menu.direction = .Up
menuView.menu.baseSize = CGSizeMake(diameter, diameter)
menuView.menu.views = [button1,button2]
view.layout(menuView).width(diameter).height(diameter).bottomRight(bottom: 58, right: 20)
}
private func prepareTabBarItem() {
//todo
}
override func viewDidLoad() {
super.viewDidLoad()
prepareMenuView()
}
}
The menu I have embedded as a subView of UINavigationController. The reason I have added to this subView is because the FAB is on top of a search/display controller (TableView) and this way the FAB can remain on top of the TableView even when scrolling the contents of the Table.
When the view initially loads, I can click on the menu button and the animation happens correctly and button2 appears. However, it does not allow me to hit the second button OR close the menu by pressing button1 again UNLESS I navigate to another tab in the tab bar controller and then navigate back to the tab where the FAB MenuView was located. I am loading my prepareMenuView() function in viewDidLoad just as it is shown in the example.
Not sure how to modify this so that it can behave as desired. It doesn't make sense to pick another ViewController lifecycle method to run prepareMenuView().
so the issue with your code is that button2 only has the selector handler for handleButton. The handleMenu handler is not added to it. So you have two solutions.
Add the handleMenu call to the handleButton
internal func handleButton(button: UIButton) {
print("Hit Button \(button)")
handleMenu(button)
}
Add a selector handler to the button2 instance for handleMenu.
button2.addTarget(self, action: #selector(handleMenu), forControlEvents: .TouchUpInside)
button2.addTarget(self, action: #selector(handleButton), forControlEvents: .TouchUpInside)
Either option will work, just remember that order matters. So if you want the menu to close before you load some content, then call the method before or add the selector handler handleMenu before you add the handleButton.
:) All the best!

Change tint image color when pressing uibutton in Swift

I have a scrollview inside a view. Inside the scrollview I create programmatically 5 buttons. Every button loads a different image with a different tag each one. I added a function that is called when pressing the buttons.
let avatarsListScrollingView = avatarsListView(CGSizeMake(70.0, 55.0), avatarCount: 5)
func avatarsListView(buttonSize:CGSize, avatarCount:Int) -> UIView {
**CODE**
for i in 0...(avatarCount-1) {
let button = UIButton(type: .Custom)
**CODE**
button.setImage(UIImage(named: avatarsList[i]), forState: .Normal)
button.tag = i
button.addTarget(self, action: "avatarListSelected:", forControlEvents: .TouchUpInside)
avatarButtonView.addSubview(button)
}
return avatarButtonView
}
Then when pressing the buttons, I call to "avatarListSelected":
func avatarListSelected(sender:UIButton){
if let image = sender.imageView?.image?.imageWithRenderingMode(.AlwaysTemplate) {
sender.setImage(image, forState: .Normal)
sender.tintColor = UIColor.redColor()
}
self.addAvatarView.reloadInputViews()
}
This function tints the image button to red, it is working fine, but the problem is that when I press some other button, I want the other one goes to the original color. Right now every button that I press gets in red.
I tried to add the call to "self.addAvatarView.reloadInputViews()" to try to "redraw" again all the buttons, but never gets called.
Do you guys know some way to do this?
Thanks to everybody!
This is the final code that solved the problem:
func avatarListSelected(sender:UIButton){
print(sender.tag)
if let image = sender.imageView?.image?.imageWithRenderingMode(.AlwaysTemplate) {
sender.setImage(image, forState: .Normal)
sender.tintColor = UIColor.redColor()
}
for view in self.avatarButtonView.subviews as [UIView] {
if let btn = view as? UIButton {
if btn.tag != sender.tag {
btn.setImage(UIImage(named: avatarsList[btn.tag]), forState: .Normal)
}
}
}
}
Create a property selectedButton: UIButton? and keep a reference to the selected button there. Don't forget to update it in avatarListSelected method and before you change it, if it isn't nil, change its color to original (and then change it).
If the buttons have different original colors, subclass UIButton class and keep the original color there.
I don't know if is better approach or answer, but, i maybe could delivery this using this approach:
Create a method that will "fill" the color for your choice button and "clear" color to others , but its a method that loop through UIScrollView and look for each UIButton. Something like this :
func setBackgroundColorButton(color:UIColor , buttonTag:Int){
for view in self.scrollView.subviews as [UIView] {
if let btn = view as? UIButton {
if btn == buttonTag {
btn.tintColor = color
} else {
btn.tintColor = UIColor.whiteColor()
}
}
}
}
This is the concept, i didn't tested, but maybe just need adjust to search inside your scroll view or similar.
But with this will be work nice i believe :D
You could do it like this
for i in 0...5 {
let button = UIButton(type: .Custom)
let x = 50 * i + 10
let y = 50
button.frame = CGRectMake(CGFloat(x), CGFloat(y), 40, 40)
button.setTitle("\(i)", forState: .Normal)
button.tag = i
button.backgroundColor = UIColor.greenColor()
button.tintColor = UIColor.blueColor()
button.addTarget(self, action: "avatarListSelected:", forControlEvents: .TouchUpInside)
self.view.addSubview(button)
}
func avatarListSelected(sender : UIButton){
sender.backgroundColor = UIColor.orangeColor()
for view in self.view.subviews{
if(view.isKindOfClass(UIButton)){
let button = view as! UIButton
if button.tag != sender.tag{
button.backgroundColor = UIColor.greenColor()
}
}
}
}
The frame etc is just for demonstation purpose only, you should of course use your own value. The tintColor property is not valid for all button types. Read the documentation for more information.

Resources