Why button appears only on the second attempt? - ios

I'm trying to add a function that will show the close button in my custom alert view.
When I call it for the first time, only an empty area appears that does not contain a button (no color, no text and no pressing). When you call again - everything works as it should.
It does not depend on the parameter animated, in both cases it works the same.
My dialogView is a my custom UIView. I don't use UIAlertController
What could be the problem?
initial view after the first attempt second attempt
GIF call func by click
func showCloseButton(text: String, animated: Bool){
let dialogViewHeight = self.dialogView.frame.height + 50 + 1
let button = UIButton(type: .roundedRect)
button.backgroundColor = .red
button.frame.origin = CGPoint(x: 0, y: dialogViewHeight)
button.frame.size = CGSize(width: self.dialogView.frame.width, height: 50)
button.setTitle(text, for: .normal)
button.addTarget(self, action: #selector(closeTapped), for: .touchUpInside)
let separatorLineView = UIView()
separatorLineView.frame.origin = CGPoint(x: 0, y: self.dialogView.frame.height)
separatorLineView.frame.size = CGSize(width: dialogView.frame.width, height: 1)
separatorLineView.backgroundColor = UIColor.groupTableViewBackground
dialogView.addSubview(separatorLineView)
if animated {
animateAdjustDialogView(height: dialogViewHeight){
Logger.Log("completion did")
self.dialogView.addSubview(button)
}
} else {
Logger.Log("button.frame.origin = \(button.frame.origin)")
Logger.Log("button.frame.size = \(button.frame.size)")
Logger.Log("button.title = \(button.titleLabel)")
self.dialogView.frame.size = CGSize(width: self.dialogView.frame.width, height: dialogViewHeight)
self.dialogView.addSubview(button)
}
}
private func animateAdjustDialogView(height: CGFloat, completion: (()->Void)?){
UIView.animate(withDuration: 1.0, animations: {
self.dialogView.frame.size = CGSize(width: self.dialogView.frame.width, height: height)
self.layoutIfNeeded()
}) { (finished) in
Logger.Log("finished = \(finished)")
if finished {
Logger.Log("completion run")
completion?()
}
}
}

Button frame is causing the issue -
button.frame.origin = CGPoint(x: 0, y: dialogViewHeight)
Where
let dialogViewHeight = self.dialogView.frame.height + 50 + 1
That means, button goes beyond dialogView frame.
So replace
button.frame.origin = CGPoint(x: 0, y: dialogViewHeight)
With
button.frame.origin = CGPoint(x: 0, y: dialogViewHeight - 50) // Height of the Button.
Let me know if you are still having any issue.

Related

UIButton loses responsivity(i.e can't press it), maybe because of CGAffineTransform

Firstly, I think that the problem is on the UIVisualEffectView, but now I think that the problem is on the CGAffineTransform that I'm using to animate the view on the openOptionsTooltip()
First, I found a similar problem on that question (see the comments on the accepted answer), but in my case I'm adding a button as subview of the UIVisualEffectView, not adding it as a button subview.
Apple documentation says:
Depending on the desired effect, the effect may affect content layered behind the view or content added to the visual effect view’s contentView.
But I can't find a better explanation on how or why it can affect the content added to the contentView.
I'm doing all the stuff programmatically, without any xib.
The visual effect view is a balloon like a tooltip that appears when I touch the titleView.
I'm creating that view on viewDidLoad and holding a
reference to it on the viewController.
After created, when I click on the titleView I'm adding it as a subview of UIWindow
Here's my code:
The method to create the view:
func createOptionsTooltip(withNamesAndActions options: [(name: String , action: Selector)]){
self.tooltipSize = CGSize(width: 250, height: CGFloat(60*options.count+12))
var optionItens : [UIView] = []
for i in 0..<options.count{
let optionView = UIView(frame: CGRect(x: .zero, y: CGFloat(60*i), width: self.tooltipSize.width, height: 60))
optionView.backgroundColor = .clear
let separatorView = UIView(frame: CGRect(x: .zero, y: 59, width: self.tooltipSize.width, height: 1))
separatorView.backgroundColor = UIColor(white: 0.8, alpha: 0.5)
let button = UIButton(frame: CGRect(x: .zero, y: .zero, width: self.tooltipSize.width, height: 59))
button.setTitle(options[i].name, for: .normal)
button.setTitleColor(self.view.tintColor, for: .normal)
button.addTarget(self, action: options[i].action, for: .touchUpInside)
button.isEnabled = true
button.isUserInteractionEnabled = true
optionView.addSubview(button)
optionView.addSubview(separatorView)
optionView.bringSubviewToFront(button)
optionItens.append(optionView)
}
self.blackOpaqueView = UIView(frame: self.view.bounds)
self.blackOpaqueView.backgroundColor = UIColor.black
self.blackOpaqueView.alpha = 0
let gesture = UITapGestureRecognizer(target: self, action: #selector(ScheduleNavigationController.closeOptionsTooltip))
// blackOpaqueView.addGestureRecognizer(gesture)
self.vwTooltip = UIView(frame: CGRect(origin: CGPoint(x: self.view.frame.midX - self.tooltipSize.width/2, y: self.view.frame.minY+self.navigationBar.frame.size.height+UIApplication.shared.statusBarFrame.height+10), size: CGSize(width: 1, height: 1)))
self.vwTooltip.transform = self.vwTooltip.transform.scaledBy(x: 1, y: 0.01)
self.vwTooltip.isHidden = true
let vwAim = UIVisualEffectView(frame: CGRect(x: self.tooltipSize.width/2 - 6, y: 0, width: 12, height: 10))
let vwBalloon = UIVisualEffectView(frame: CGRect(x: 0, y: vwAim.frame.size.height, width: self.tooltipSize.width, height: CGFloat(60*options.count)))
vwBalloon.cornerRadius = 8
vwBalloon.contentView.isUserInteractionEnabled = true
vwBalloon.isUserInteractionEnabled = true
let bezPath = trianglePathWithCenter(rect: vwAim.frame)
let maskForPath = CAShapeLayer()
maskForPath.path = bezPath.cgPath
vwAim.layer.mask = maskForPath
vwBalloon.effect = UIBlurEffect(style: .prominent)
vwAim.effect = UIBlurEffect(style: .prominent)
for optionView in optionItens{
vwBalloon.contentView.addSubview(optionView)
vwBalloon.bringSubviewToFront(optionView)
}
self.vwTooltip.addSubview(vwBalloon)
self.vwTooltip.addSubview(vwAim)
self.vwTooltip.bringSubviewToFront(vwBalloon)
vwBalloon.bringSubviewToFront(vwBalloon.contentView)
}
And I'm calling't on the viewDidLoad that way:
createOptionsTooltip(withNamesAndActions: [("Sair", #selector(ScheduleNavigationController.closeSchedule(_:))), ("Hoje", #selector(ScheduleNavigationController.scrollToToday(_:)))])
And I'm open the tooltip animated this way:
func openOptionsTooltip(){
if let appDelegate = UIApplication.shared.delegate as? AppDelegate{
appDelegate.window?.addSubview(blackOpaqueView)
appDelegate.window?.addSubview(vwTooltip)
appDelegate.window?.bringSubviewToFront(vwTooltip)
UIView.animate(withDuration: 0.2, animations: {
self.blackOpaqueView.alpha = 0.5
}) { _ in
self.vwTooltip.isHidden = false
UIView.animate(withDuration: 0.1, animations: {
self.vwTooltip.transform = self.vwTooltip.transform.scaledBy(x: 1, y: 100)
})
}
}
}
What I have tried:
Bring the buttons and all it's superview in hierarch to front using bringSubviewToFront. (I have checked, there's no view on the front of the button)
change the isUserInteractEnabled for all button superviews in hierarch.(for both false and true)
Change the way that I'm adding the target to buttons, without using the method parameter.
Change the selector method to any other method that work on other targets and switch the method between #objc and #IBOulet
Change the buttons to a view other than the UIVisualEffectView
PS: I found that the UIVisualEffectView has 3 subviews, but apparently the contentView is the above view, see the log of printing it's subviews:
▿ 3 elements
- 0 : <_UIVisualEffectBackdropView: 0x102dcd140; frame = (0 0; 250 120); autoresize = W+H; userInteractionEnabled = NO; layer = <UICABackdropLayer: 0x280d1b480>>
- 1 : <_UIVisualEffectSubview: 0x102dcd350; frame = (0 0; 250 120); autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x280d15c80>>
- 2 : <_UIVisualEffectContentView: 0x102dcc940; frame = (0 0; 250 120); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x280d1ace0>>
I can't figure out what is blocking the button's user interaction
Here's the result:
I have found the problem:
After calling the openOptionsTooltip() the transform inside't are resizing all it's subview, but the vwTooltp itself don't change it's frames, but because it clipToBounds property are false, all the subviews are showing, but the user can't access the button actions because the view has 1x1 size. Changing the openOptionsTooltip() method to that:
func openOptionsTooltip(){
if let appDelegate = UIApplication.shared.delegate as? AppDelegate{
appDelegate.window?.addSubview(blackOpaqueView)
appDelegate.window?.addSubview(vwTooltip)
appDelegate.window?.bringSubviewToFront(vwTooltip)
UIView.animate(withDuration: 0.2, delay: 0.0, options: UIView.AnimationOptions.allowUserInteraction, animations:{
self.blackOpaqueView.alpha = 0.5
}) { _ in
self.vwTooltip.isHidden = false
UIView.animate(withDuration: 0.1, delay: 0.0, options: UIView.AnimationOptions.allowUserInteraction, animations:{
self.vwTooltip.transform = self.vwTooltip.transform.translatedBy(x: 1, y: 1)
self.vwTooltip.transform = self.vwTooltip.transform.scaledBy(x: 1, y: 100)
}){ _ in
self.vwTooltip.frame = self.tooltipFrame
}
}
}
}
And now it's working properly. Thanks for the responses

Assign tags for dynamic UIButtons

I found this example of a dynamic view of UIButtons at: http://helpmecodeswift.com/advanced-functions/generating-uibuttons-loop
I inserted this code into my app but unfortunately I can't find a way to set a tag for each buttons.
My target is to know which button is tapped, count the amount of clicks for each button and save this information into my DB.
override func viewDidLoad() {
super.viewDidLoad()
var arrayOfVillains = ["santa", "bugs", "superman", "batman"]
var buttonY: CGFloat = 20
for villain in arrayOfVillains {
let villainButton = UIButton(frame: CGRect(x: 50, y: buttonY, width: 250, height: 30))
buttonY = buttonY + 50 // we are going to space these UIButtons 50px apart
villainButton.layer.cornerRadius = 10 // get some fancy pantsy rounding
villainButton.backgroundColor = UIColor.darkGrayColor()
villainButton.setTitle("Button for Villain: \(villain)", forState: UIControlState.Normal) // We are going to use the item name as the Button Title here.
villainButton.titleLabel?.text = "\(villain)"
villainButton.addTarget(self, action: "villainButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(villainButton) // myView in this case is the view you want these buttons added
}
}
func villainButtonPressed(sender:UIButton!) {
if sender.titleLabel?.text != nil {
println("You have chosen Villain: \(sender.titleLabel?.text)")
} else {
println("Nowhere to go :/")
}
}
}
So how it is possible to set and get the tag for/from each button in code (in this example)?
Thank you in advance!
You can use enumerated array to access indexes of the current item in iteration and use that as a tag:
override func viewDidLoad() {
super.viewDidLoad()
var arrayOfVillains = ["santa", "bugs", "superman", "batman"]
var buttonY: CGFloat = 20
for (index, villain) in arrayOfVillains.enumerated() {
let villainButton = UIButton(frame: CGRect(x: 50, y: buttonY, width: 250, height: 30))
buttonY = buttonY + 50 // we are going to space these UIButtons 50px apart
// set the tag to current index
villainButton.tag = index
villainButton.layer.cornerRadius = 10 // get some fancy pantsy rounding
villainButton.backgroundColor = UIColor.darkGrayColor()
villainButton.setTitle("Button for Villain: \(villain)", forState: UIControlState.Normal) // We are going to use the item name as the Button Title here.
villainButton.titleLabel?.text = "\(villain)"
villainButton.addTarget(self, action: "villainButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(villainButton) // myView in this case is the view you want these buttons added
}
}
}
#objc func villainButtonPressed(sender:UIButton!) {
// tag of pressed button
print(">>> you pressed button with tag: \(sender.tag)")
if sender.titleLabel?.text != nil {
println("You have chosen Villain: \(sender.titleLabel?.text)")
} else {
println("Nowhere to go :/")
}
}
You should use an integer-based for loop for this.
for i in 0 ..< arrayOfVillains.count {
let villain = arrayOfVillains[i]
let villainButton = UIButton(frame: CGRect(x: 50, y: buttonY, width: 250, height: 30))
villainButton.tag = i
}
You can do as follows,
var buttonTag = 1
for villain in arrayOfVillains {
let villainButton = UIButton(frame: CGRect(x: 50, y: buttonY, width: 250, height: 30))
villainButton.tag = buttonTag
buttonTag += 1
}

How can I properly place a UIButton on top of a loaded SFSafariViewController?

I have read many articles about the SFSafariViewController and I believe that it offers splendid functionality in iOS apps. However, when I load my SFSafariViewController, I intentionally hide the navigation bar because I want one custom fixed button in the upper left corner to dismiss the view controller.
override func viewDidAppear(_ animated: Bool) {
let safariViewController = PSSafariViewController(url: URL(string: blogUrl)!, entersReaderIfAvailable: true)
present(safariViewController, animated: false) {
var frame = safariViewController.view.frame
let OffsetY: CGFloat = 44
frame.origin = CGPoint(x: frame.origin.x, y: frame.origin.y - OffsetY)
frame.size = CGSize(width: frame.width, height: frame.height + OffsetY)
safariViewController.view.frame = frame
let btn: UIButton = UIButton(frame: CGRect(x: 100, y: 400, width: 100, height: 50))
btn.backgroundColor = UIColor.green
btn.setTitle("Click Me", for: .normal)
btn.addTarget(self, action: #selector(PSBlogViewController.buttonAction), for: UIControlEvents.touchUpInside)
btn.tag = 1 // change tag property
btn.isOpaque = true
safariViewController.view.addSubview(btn)
safariViewController.view.bringSubview(toFront: btn)
print(btn.description)
}
}
As you can see, I alter the frame so that the bar at the top is not visible. That code runs fine. But when I try to add a UIButton, it appears briefly and then is covered when I run the app. It's a simple blog reader app that uses the SFSafariViewController. Maybe Apple doesn't want developers running around messing with this, but any solutions or workarounds to make the button stay visible are greatly appreciated!
Here's the info about the button: 0x7f950b618db0; frame = (100 400; 100 50); tag = 1; layer = CALayer: 0x60000023ab60
Why don't you use one of the other WebView classes to get the extra functionalities you desire?
5.1.1 (iv) SafariViewContoller must be used to visibly present information to users; the controller may not be hidden or obscured by
other views or layers. Additionally, an app may not use
SafariViewController to track users without their knowledge and
consent.
It is definitely true that Apple won't want the SFSafariViewController to be obscured. However, I did figure out that when I present it, in the completion block I can add a button and what was causing trouble was that I had to increase the zPosition of the layer of the button's view like so:
present(safariViewController, animated: false) {
var frame = safariViewController.view.frame
let OffsetY: CGFloat = 44
frame.origin = CGPoint(x: frame.origin.x, y: frame.origin.y - OffsetY)
frame.size = CGSize(width: frame.width, height: frame.height + OffsetY)
safariViewController.view.frame = frame
self.btn = UIButton(frame: CGRect(x: 5, y: 50, width: 50, height: 50))
self.btn.layer.cornerRadius = 25
self.btn.backgroundColor = UIColor(red: 0, green: 170/255, blue: 240/255, alpha: 0.5)
self.btn.setTitle("←", for: .normal)
self.btn.addTarget(self, action: #selector(safariViewController.buttonAction(sender:)), for: .touchUpInside)
self.btn.tag = 1 // change tag property
self.btn.isOpaque = true
safariViewController.view.addSubview(self.btn)
safariViewController.view.bringSubview(toFront: self.btn)
self.btn.layer.zPosition = safariViewController.view.layer.zPosition + 1
for subview in safariViewController.view.subviews {
subview.isUserInteractionEnabled = false
}
self.btn.isEnabled = true
self.btn.isUserInteractionEnabled = true
//print(self.btn.description)
}

Create an "add-player" view - Swift

I'm creating a game where the player has the possibility to add several players on a view controller :
Actually, I can add a new player and remove it :
The problem appears when I remove a player :
I want player 2 and player 3 goes below the textField "Name when I remove a player. How can I do this ?
ViewDidLoad :
// MARK: ADD BUTTON
let addButtonSize = CGSize(width: topPartSize.height, height: topPartSize.height)
let addButton = UIButton(frame: CGRect(x: enterPlayerPartSize.width - addButtonSize.width, y: 0, width: addButtonSize.width, height: addButtonSize.height))
addButton.titleLabel!.font = UIFont.fontAwesomeOfSize(addButtonSize.height / 2)
addButton.setTitle(String.fontAwesomeIconWithName(.Plus), forState: .Normal)
addButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
addButton.setTitleColor(UIColor(red: 1, green: 1, blue: 1, alpha: 0.5), forState: .Highlighted)
addButton.titleLabel?.textAlignment = .Center
addButton.layer.zPosition = 3
addButton.addTarget(self, action: #selector(PlayersViewController.addPlayer(_:)), forControlEvents: .TouchUpInside)
enterPlayerPart.addSubview(addButton)
// MARK: TEXT FIELD
let textFieldSize = CGSize(width: enterPlayerPartSize.width - playerIconSize.width - addButtonSize.width, height: enterPlayerPartSize.height)
textField = UITextField(frame: CGRect(x: playerIconSize.width, y: 0, width: textFieldSize.width, height: textFieldSize.height))
textField.font = UIFont(name: "Avenir-Light", size: textFieldSize.height / 2)
textField.attributedPlaceholder = NSAttributedString(string:"Name", attributes:[NSForegroundColorAttributeName: UIColor(red: 1, green: 1, blue: 1, alpha: 0.5)])
textField.textColor = UIColor.whiteColor()
textField.textAlignment = NSTextAlignment.Left
textField.returnKeyType = UIReturnKeyType.Done
textField.delegate = self
enterPlayerPart.addSubview(textField)
Functions :
// MARK: ADD PLAYER - FUNCTION
func addPlayer(sender: UIButton) {
if textField.text == nil || textField.text == "" {
print("Enter player name")
} else {
createNewPlayer(textField.text!)
}
}
// MARK: CREATE NEW PLAYER - FUNCTION
func createNewPlayer(playerName: String) {
let playerPartSize = CGSize(width: screenWidth, height: screenHeight * 0.1)
let playerPart = UIView(frame: CGRect(x: 0, y: playerPartSize.height * CGFloat(playersCount), width: playerPartSize.width, height: playerPartSize.height))
scrollView.addSubview(playerPart)
// PLAYER ICON
let playerIconSize = CGSize(width: playerPartSize.height, height: playerPartSize.height)
let playerIcon = UILabel(frame: CGRect(x: 0, y: 0, width: playerIconSize.width, height: playerIconSize.height))
playerIcon.font = UIFont.fontAwesomeOfSize(topPartSize.height / 2)
playerIcon.text = String.fontAwesomeIconWithName(.User)
playerIcon.textAlignment = .Center
playerIcon.textColor = UIColor.whiteColor()
playerPart.addSubview(playerIcon)
// REMOVE BUTTON
let removeButtonSize = playerIconSize
let removeButton = UIButton(frame: CGRect(x: playerPartSize.width - removeButtonSize.width, y: 0, width: playerIconSize.width, height: playerIconSize.height))
removeButton.titleLabel!.font = UIFont.fontAwesomeOfSize(removeButtonSize.height / 2)
removeButton.setTitle(String.fontAwesomeIconWithName(.Trash), forState: .Normal)
removeButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
removeButton.setTitleColor(UIColor(red: 1, green: 1, blue: 1, alpha: 0.5), forState: .Highlighted)
removeButton.titleLabel?.textAlignment = .Center
removeButton.addTarget(self, action: #selector(PlayersViewController.removePlayer(_:)), forControlEvents: .TouchUpInside)
playerPart.addSubview(removeButton)
// PLAYER NAME
let playerNameSize = CGSize(width: playerPartSize.width - playerIconSize.width - removeButtonSize.width, height: playerPartSize.height)
let playerNameLabel = UILabel(frame: CGRect(x: playerIconSize.width, y: 0, width: playerNameSize.width, height: playerNameSize.height))
playerNameLabel.font = UIFont(name: "Avenir-Light", size: playerNameSize.height / 2)
playerNameLabel.text = playerName
playerNameLabel.textAlignment = .Left
playerNameLabel.textColor = UIColor.whiteColor()
playerPart.addSubview(playerNameLabel)
// BOTTOM LINE
let bottomLineHeight = playerPartSize.height / 50
let bottomLine = UIView(frame: CGRect(x: 0, y: playerPartSize.height - bottomLineHeight, width: playerPartSize.width, height: bottomLineHeight))
bottomLine.backgroundColor = UIColor(hexColor: 0x1B1B1B)
playerPart.addSubview(bottomLine)
// PLAYERS COUNT ++
playersCount += 1
}
Thanks for your help !
You have two ways to perform it :
You seem using reusable components, so you should have a look on UITableView / UICollectionView. It will manage memory usage, and components layout
If you dont want to migrate to theses components, it recommend you to store all your player views in an array, and relayout them after an add/remove operation
something like :
var players : [UIView] = []
func createNewPlayer(playerName: String) {
//Do your stuff here
players.append(newCreatedPalyerView)
layout()
}
func layout() {
var yPosition = 0
for view in players {
view.frame.origin.y = yPosition
yPosition += view.frame.size.height
}
}
func removePlayer(player : UIView) {
self.players.remove(player)
self.layout()
}
You need to manage your scenario something like below :
First take all the UI of one player in one UIView. So you should have all your one player's stuff(playername label, remove button etc) in one view. (i think you have it in playerPart - that`s cool)
Now you are adding that playerPart directly in scrollview i think, If it is like that then you should not do like this. You should have one UIView of same size of scrollview in scrollview(same as content size of scrollview) and you should add playerPart to that view.
Now you can get all subviews of that view in array something like :
NSArray *viewArr = [tempView subviews];
Assume tempView is vied over scrollview as i have mentioned above,
you can get subview of scrollview also by calling same method.
Now for example you have four player(four view) in view (temp view or scrollview if tempview is not added on it) and you click remove on player 3 then you can get index of that object from that view array. for example,
you have array of total view which you have get from
NSArray *viewArr = [tempView subviews];
then you can get index of player3 i.e view3 like,
int index = [viewArr indexOfObject:player3];
now make one method or function which is called after every removed call and pass that index as parameter in that method.
In that method take one for loop, which start from this index and run till last object (view) of this viewArr. Decrease y of every coming view in this for loop so your all view which was belowed removed view will goes up.
Here is one my method i was using in my one project to remove view and manage other accordingly :
#pragma mark UpdateFrameOfViews
-(void)updateFrameOfViewWithTag : (int) myTag increament : (CGFloat)increament fromIndex : (int)index{
CustomSubClassView *tempView = [self.view viewWithTag:myTag];
UIScrollView *tempScroll = (UIScrollView*)[tempView superview];
NSArray *subViews = [tempView subviews];
BOOL status = NO;
for (int i = index; i <= subViews.count; i++) {
if (i < subViews.count) {
UIView *tempView1 = [subViews objectAtIndex:i];
CGFloat newY = tempView1.frame.origin.y + increament;
CGRect newFrame = CGRectMake(tempView1.frame.origin.x, newY, tempView1.frame.size.width, tempView1.frame.size.height);
tempView1.frame = newFrame;
status = YES;
}
if (index == subViews.count && i == subViews.count) {
// UIView *tempView1 = [subViews lastObject];
//
// CGFloat newY = tempView1.frame.origin.y + increament;
//
// CGRect newFrame = CGRectMake(tempView1.frame.origin.x, newY, tempView1.frame.size.width, tempView1.frame.size.height);
//
// tempView1.frame = newFrame;
status = YES;
}
// tempView1.backgroundColor = [UIColor orangeColor];
}
if (status) {
CGRect containerFrame = CGRectMake(0, 0, self.view.frame.size.width, tempView.frame.size.height+increament);
tempView.frame = containerFrame;
tempScroll.contentSize = CGSizeMake(tempView.frame.size.width, tempView.frame.size.height);
}
}
This method is for reference just, because here scenario is little bit different.
My code is in objective and is for reference only convert in swift required!!
This was how you manage it!!
Suggestion : it is better to use UITableView in your case!!!
Hope this will help :)

center element when pressed in a ScrollView

i really how to do a thing wich is probably easy..
I've a ScrollView with some button in it.
That's how i create all my button in the scrollview.
var buttonList = [UIButton]()
func createButton() {
let imageArray = fillImageArray()
var lastButtonWidth: CGFloat = 0
for index in 0..<6 {
let frame1 = CGRect(x: ((self.view.frame.size.width / 2) - 27.5) + CGFloat(index * 70), y: 0, width: 55, height: 55 )
let button = UIButton(frame: frame1)
button.setImage(imageArray[index], forState: .Normal)
button.tag = index
button.addTarget(parentViewController, action: #selector(ViewController.buttonClicked(_:)), forControlEvents: .TouchUpInside)
self.scrollView.addSubview(button)
lastButtonWidth = frame1.origin.x
buttonList.append(button)
}
self.scrollView.contentSize = CGSizeMake(lastButtonWidth + 55, 0)
}
I want when i press one of my button to center him and positioning correctly the other buttons.
example :
If i press on 5 i want this result :
the button 5 is moved to the center.
Now what I would suggest using is the scroll view method scrollView.scrollRectToVisible(CGRect, animated: Bool). This will move the scroll view to make a certain part of your content visible.
To create the CGRect you could do something like this:
let scrollWidth = scrollView.frame.width
let scrollHeight = scrollView.frame.height
let desiredXCoor = button.frame.origin.x - ((scrollWidth / 2) - (button.frame.width / 2) )
let rect = CGRect(x: desiredXCoor, y: 0, width: scrollWidth, height: scrollHeight)
scrollView.scrollRectToVisible(rect, animated: true)
My math may be a bit off, but the essence is that you use the size of the scrollView and the UIButton to create a CGRect for the scroll view to move to. This means when a button is clicked, you could use an implementation like this:
func myMethod() {
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
}
func buttonClicked(sender: UIButton){
let scrollWidth = scrollView.frame.width
let scrollHeight = scrollView.frame.height
let desiredXCoor = sender.frame.origin.x - ((scrollWidth / 2) - (sender.frame.width / 2) )
let rect = CGRect(x: desiredXCoor, y: 0, width: scrollWidth, height: scrollHeight)
scrollView.scrollRectToVisible(rect, animated: true)
}
If adjusted properly to your project, this should allow you to do what you have outlined.
Hope this would help you.
In button action method write below code.
func buttonClicked(sender:UIButton) {
for view in self.scrollView.subviews {
if view.isKindOfClass(UIButton) && view.tag == sender.tag {
let xCenter = max(0, (view.center.x - self.scrollView.frame.width/2))
self.scrollView.setContentOffset(CGPointMake(xCenter, self.scrollView.contentOffset.y), animated: true)
break;
}
}
}
I suppose you want the button touched to be placed in the center,so there is a easy solution, you can use the button's center.x - scrollview.width / 2 as the offsetX to construct the contentOffset and take two boundary situation into consideration:offsetx < 0 and offsetx + scrollview.width > scroll.contentSize.width
Ok i just found by myself.
let centerScrollView = scrollView.frame.size.height * 2
UIView.animateWithDuration(0.2, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: {
self.scrollView.contentOffset = CGPoint(x: sender.frame.origin.x - centerScrollView, y: sender.frame.origin.y)
}, completion: nil)
and it's perfectly center. Thx everyone.

Resources