Adjust popOverViewController to the size of the label.text - ios

So i have a popover yet i cant manage to configure the right size:
So this is the popover class:
final class PopOverViewController: UIViewController {
#IBOutlet weak var lbl: UILabel!
var text: String?
init(text: String) {
super.init(nibName: "PopOverViewController", bundle: nil)
self.text = text
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
lbl.text = text
//lbl.sizeToFit()
// self.view.frame = lbl.frame
}
}
The label is align to x and y center.
The invoke is :
fileprivate func showTipIfNedded() {
let optionItemListVC = PopOverViewController(text: "qewlghsflgha;lgh;lkfgj")
optionItemListVC.modalPresentationStyle = .popover
optionItemListVC.view.backgroundColor = .red
if let popover = optionItemListVC.popoverPresentationController {
popover.sourceView = self.view
popover.permittedArrowDirections = .down
//popover.containerView?.backgroundColor = .red
guard let firstTab = tabBarController?.tabBar.items?[0].value(forKey: "view") as? UIView else { return }
popover.sourceRect = CGRect(x: firstTab.frame.midX, y: (self.tabBarController?.tabBar.frame.minY)!, width: 1, height: 1)
optionItemListVC.preferredContentSize = CGSize(width: optionItemListVC.lbl.frame.width, height: optionItemListVC.lbl.frame.height)
popover.delegate = self
}
self.present(optionItemListVC, animated: true, completion: nil)
}
With the current constraint the vc is small an i cant see the whole text, with constraint thet are 50 to all side the vc is to big, more then needed.
What constraints must i build? and are there more things i should config?

In your PopoverViewController override preferredContentSize to control the size of the view controller, something like this:
import UIKit
class PopoverViewController: UIViewController
{
#IBOutlet weak var lbl: UILabel!
override func viewDidLoad()
{
super.viewDidLoad()
...
}
// Preferred content size
override var preferredContentSize: CGSize
{
get
{
// measure
let maxLabel: CGSize = CGSize.init(width: lbl.frame.size.width, height: CGFloat.greatestFiniteMagnitude)
let fittingSize: CGSize = lbl.sizeThatFits(maxLabel)
// add some margins/padding, margins = 8 horizontal = 12 vertical
return CGSize.init(width: fittingSize.width + 16, height: fittingSize.height + 24)
}
set
{
super.preferredContentSize = newValue
}
}
}
The getter measures the size of the UILabel (assuming its already populated with text), adding some vertical and horizontal padding

Related

Not able to show border color and background as blur in custom view as popup view in Swift

I have some requirement to show popup as some customisation options.
So, I took custom view as UIView with Xib file.
class CustomAlertView : UIView {
#IBOutlet weak var customAlertView : UIView!
#IBOutlet weak var button1 : UIButton!
#IBOutlet weak var button2 : UIButton!
override init(frame: CGRect) { // for using CustomView in code
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) { // for using CustomView in IB
super.init(coder: aDecoder)
self.commonInit()
}
private func commonInit() {
Bundle.main.loadNibNamed("CustomAlertView", owner: self)
guard let content = customAlertView else { return }
content.frame = self.bounds
content.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.addSubview(content)
}
}
And given outlet connections.
And I am able to load the view in viewcontroller class.
But, the issue is, its not showing as pop up view and its not showing any border color, etc even I added too.
And the present self.view (Main view from viewcontroller) still moving it has tableview, while I clicking on the buttons on custom view, nothing happening.
func someAction() {
self.view.addSubview(customAlert)
self.customAlert.layer.cornerRadius = 13
self.customAlert.layer.borderWidth = 10
self.customAlert.layer.borderColor = UIColor.gray.cgColor
self.customAlert.clipsToBounds = false
let radius: CGFloat = self.customAlert.frame.width / 2.0 //change it to .height if you need spread for height
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: self.customAlert.frame.height))
self.customAlert.layer.masksToBounds = false
self.customAlert.layer.cornerRadius = 8; // if you like rounded corners
self.customAlert.layer.shadowOffset = CGSize(width:-15, height:20);
self.customAlert.layer.shadowRadius = 5;
self.customAlert.layer.shadowOpacity = 0.5;
self.customAlert.layer.shadowPath = shadowPath.cgPath
self.customAlert.byMonthlyBtn.addTarget(self, action: #selector(button1tapped), for: .touchUpInside)
self.customAlert.byAnnuallyBtn.addTarget(self, action: #selector(button2tapped), for: .touchUpInside)
}
And its looks like below screenshot
Any suggestions?
private func commonInit() {
Bundle.main.loadNibNamed("CustomAlertView", owner: self)
guard let content = customAlertView else { return }
content.frame = self.bounds
content.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.addSubview(content)
}
Your problem is you are using the CustomAlertView you loaded. Try adjust your code like below.
private func commonInit() {
guard let view = Bundle.main.loadNibNamed("CustomAlertView", owner: self)?.first as? CustomAlertView else {
return
}
view.frame = bounds
view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
addSubview(view)
}

Cannot change navigation bar item height in iOS 11

After customizing the navigation bar height bigger than the default value (44pt), I want to change the height of my right side navigation bar item button, but it's limited in 44pt. How can I make it taller? I know that in iOS 11, the button now is inside a UIBarButtonStackView, it seems we cannot change the stack view frame?
I use this code to change the width and height of the button:
button.widthAnchor.constraint(equalToConstant: 40).isActive = true
button.heightAnchor.constraint(equalToConstant: 60).isActive = true
button.translatesAutoresizingMaskIntoConstraints = false
button.setImage(image, for: .normal)
let barButton = UIBarButtonItem(customView: button)
self.navigationItem.rightBarButtonItem = barButton
Thank you!
You can change the width of navigation bar button item by using this code -
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var frame: CGRect? = navigationItem.leftBarButtonItem?.customView?.frame
frame?.size.width = 5 // change the width of your item bar button
self.navigationItem.leftBarButtonItem?.customView?.frame = frame!
}
override var prefersStatusBarHidden : Bool {
return true
}
Or from storyboard -
Make sure your Assets.xcassets image is set as Render As - Original Image Just like -
Using subclass of UInavigationcontroller class and NavigationBar class you can achieve this.
I am sharing some code of snipt:
class ARVNavigationController {
init(rootViewController: UIViewController) {
super.init(navigationBarClass: AVNavigationBar.self, toolbarClass: nil)
viewControllers = [rootViewController] }}
class AVNavigationBar {
let AVNavigationBarHeight: CGFloat = 80.0
init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initialize()
}
init(frame: CGRect) {
super.init(frame: frame ?? CGRect.zero)
initialize()
}
func initialize() {
transform = CGAffineTransform(translationX: 0, y: +AVNavigationBarHeight)
}
func layoutSubviews() {
super.layoutSubviews()
let classNamesToReposition = ["_UINavigationBarBackground", "UINavigationItemView", "UINavigationButton"]
for view: UIView? in subviews() {
if classNamesToReposition.contains(NSStringFromClass(view.self)) {
let bounds: CGRect = self.bounds()
let frame: CGRect? = view?.frame
frame?.origin.y = bounds.origin.y + CGFloat(AVNavigationBarHeight)
frame?.size.height = bounds.size.height - 20.0
view?.frame = frame ?? CGRect.zero
}
}
}
func position(for bar: UIBarPositioning) -> UIBarPosition {
return .topAttached
}
}

iOS Dynamic Content View inside ScrollView not scrolling properly

I have created a ViewController that has ScrollView direct child of its View now I have added a View inside ScrollView that has constrains :
I have added a VerticalLayout class with following code:
class VerticalLayout: UIView {
var yOffsets: [CGFloat] = []
var heightValue : CGFloat = 0.0
init(width: CGFloat) {
super.init(frame: CGRect(x:0, y:0, width:width, height:0))
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
var height: CGFloat = 0
for i in 0..<subviews.count {
let view = subviews[i] as UIView
view.layoutSubviews()
height += yOffsets[i]
view.frame.origin.y = height
height += view.frame.height
}
self.frame.size.height = height
self.heightValue = height
}
override func addSubview(_ view: UIView) {
yOffsets.append(view.frame.origin.y)
super.addSubview(view)
}
func removeAll() {
for view in subviews {
view.removeFromSuperview()
}
yOffsets.removeAll(keepingCapacity: false)
}
}
And ViewController code as :
class ViewController: UIViewController {
#IBOutlet var contentview: UIView!
#IBOutlet var scrollview: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
contentview.backgroundColor = UIColor.lightGray
let vLayout = VerticalLayout(width: view.frame.width)
vLayout.backgroundColor = UIColor.cyan
contentview.addSubview(vLayout)
vLayout.addSubview(getView(color: UIColor.red))
vLayout.addSubview(getView(color: UIColor.magenta))
vLayout.addSubview(getView(color: UIColor.green))
vLayout.addSubview(getView(color: UIColor.blue))
vLayout.addSubview(getView(color: UIColor.yellow))
contentview.frame.size.height = vLayout.heightValue
contentview.layoutIfNeeded()
}
func getView(color:UIColor) -> UIView
{
let view = UIView(frame: CGRect(x:100, y:50, width:100, height:100))
view.backgroundColor = color
return view
}
}
But when I run this code I get this screen:
And the content of this screen is not scrollable. What am I missing?
This works well with me , Also I think that vertical UIStackView is perfect for issues like that instead of manually handling views
class ViewController: UIViewController{
#IBOutlet var contentview: UIView!
#IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
contentview.backgroundColor = UIColor.lightGray
let vLayout = VerticalLayout(width: view.frame.width)
vLayout.backgroundColor = UIColor.cyan
contentview.addSubview(vLayout)
vLayout.addSubview(getView(color: UIColor.red))
vLayout.addSubview(getView(color: UIColor.magenta))
vLayout.addSubview(getView(color: UIColor.green))
vLayout.addSubview(getView(color: UIColor.blue))
vLayout.addSubview(getView(color: UIColor.yellow))
vLayout.addSubview(getView(color: UIColor.red))
vLayout.addSubview(getView(color: UIColor.magenta))
vLayout.addSubview(getView(color: UIColor.green))
vLayout.addSubview(getView(color: UIColor.blue))
vLayout.addSubview(getView(color: UIColor.yellow))
vLayout.addSubview(getView(color: UIColor.red))
vLayout.addSubview(getView(color: UIColor.magenta))
vLayout.addSubview(getView(color: UIColor.green))
vLayout.addSubview(getView(color: UIColor.blue))
vLayout.addSubview(getView(color: UIColor.yellow))
}
func getView(color:UIColor) -> UIView
{
let view = UIView(frame: CGRect(x:100, y:50, width:100, height:100))
view.backgroundColor = color
return view
}
}
class VerticalLayout: UIView {
var yOffsets: [CGFloat] = []
var heightValue : CGFloat = 0.0
init(width: CGFloat) {
super.init(frame: CGRect(x:0, y:0, width:width, height:0))
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
var height: CGFloat = 0
for i in 0..<subviews.count {
let view = subviews[i] as UIView
view.layoutSubviews()
height += yOffsets[i]
view.frame.origin.y = height
height += view.frame.height
}
// main edit is here
self.frame.size.height = height
self.heightValue = height
let ff = self.superview
let dd = ff?.superview as! UIScrollView
dd.contentSize = CGSize.init(width: self.frame.size.width, height: height)
}
override func addSubview(_ view: UIView) {
yOffsets.append(view.frame.origin.y)
super.addSubview(view)
}
func removeAll() {
for view in subviews {
view.removeFromSuperview()
}
yOffsets.removeAll(keepingCapacity: false)
}
}
Here You are missing scroll view content size. Please set scrollview content size after adding views.
scrollView.contentSize = CGSize(width: height of total no of views, height: width of the screen)
You just set constraint of content view as like
Top to super view
leading to a super view
trailing to a super view
bottom to super view
Equal width to a super view
Equal height to super view
And the last in tap on equal height constraint and set low priority(250).
Your scroll will work perfectly.

Variables is nil in awakeFromNib

I created a custom UIView that I instantiate with an object ConnectDetailItem.
Code of my custom view :
class InfosConnectView: UIView {
var view: UIView!
#IBOutlet weak var categorie: UILabel!
#IBOutlet weak var distance: UILabel!
#IBOutlet weak var followers: UILabel!
#IBOutlet weak var descriptionTextView: UITextView!
var connectDetailsItem:ConnectDetailsItem!
convenience init(connectDetailsItem:ConnectDetailsItem, frame:CGRect) {
self.init(frame: frame)
self.connectDetailsItem = connectDetailsItem
xibSetup()
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
func xibSetup() {
view = loadViewFromNib()
// use bounds not frame or it'll be offset
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
view.layer.borderWidth = 1
view.layer.borderColor = UIColor(hex: "#DDDDDD").cgColor
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "viewInfosConnect", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
override func awakeFromNib() {
super.awakeFromNib()
//Infos Connect
self.categorie.text = "\(self.connectDetailsItem.category)"
self.categorie.text = "\(self.connectDetailsItem.category)"
if (self.connectDetailsItem.distance < 1000) {
self.distance.text = "\(self.connectDetailsItem.distance) m"
} else {
let distance:NSString = NSString(format: "%.01f", Float(self.connectDetailsItem.distance)/1000)
self.distance.text = "\(distance) km"
}
if(self.connectDetailsItem.followCount < 2) {
if(self.connectDetailsItem.followCount < 1) {
self.followers.text = "0 abonné"
} else {
self.followers.text = "\(self.connectDetailsItem.followCount) abonné"
}
} else {
self.followers.text = "\(self.connectDetailsItem.followCount) abonnés"
}
self.descriptionTextView.text = self.connectDetailsItem.description
}
}
In awakeFromNib(), connectDetailItem is nil. Why ?
I instanciate my view like this : let viewInfos = InfosConnectView(connectDetailsItem: self.connectDetailsItem, frame: CGRect(x: 0, y: 9, width: self.view.frame.width, height: 200))
I set breakpoints and before entering the awakeFromNib function connectDetailItem is not nil.
I have found the solution.
I put the code in the function loadViewFromNib like this :
func loadViewFromNib() -> InfosConnectView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "viewInfosConnect", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! InfosConnectView
//Infos Connect
view.categorie.text = "\(self.connectDetailsItem.category)"
if (self.connectDetailsItem.distance < 1000) {
view.distance.text = "\(self.connectDetailsItem.distance) m"
} else {
let distance:NSString = NSString(format: "%.01f", Float(self.connectDetailsItem.distance)/1000)
view.distance.text = "\(distance) km"
}
if(self.connectDetailsItem.followCount < 2) {
if(self.connectDetailsItem.followCount < 1) {
view.followers.text = "0 abonné"
} else {
view.followers.text = "\(self.connectDetailsItem.followCount) abonné"
}
} else {
view.followers.text = "\(self.connectDetailsItem.followCount) abonnés"
}
view.descriptionTextView.text = self.connectDetailsItem.description
return view
}

IOS 6 to Swift2 update Slider

any chance someone to help me in this code? it is a Slider that changes the size of the Fonts in a Label. this worked in IOS6 but I am trying to run on Swift 2.Thanks in advance.
import UIKit
class ViewController: UIViewController {
#IBAction func defaultSlider1(sender: UISlider) {
UISlider *slide = (UISlider *)sender;
int fonts = (int)(slide.value);
NSString *newtext = NSlog("%d", fonts);
label.font = [UIFont systemFontOfSize:fonts];
label.text = newtext;
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Please try following example (Demo):
import UIKit
class ViewController: UIViewController {
private var slider: UISlider!
private var label: UILabel!
private let minimumFontSize: Float = 16
private let maximumFontSize: Float = 48
override func viewDidLoad() {
super.viewDidLoad()
let width: CGFloat = view.bounds.width / 2
let height: CGFloat = 44.0
let size = CGSize(width: width, height: height)
let origin = CGPoint(x: self.view.center.x - (width / 2), y: self.view.center.y)
createSlider(origin, size: size)
createLabel(origin, size: size)
sliderAction()
}
func createSlider(origin: CGPoint, size: CGSize) {
let frame = CGRect(origin: origin, size: size)
self.slider = UISlider(frame: frame)
self.slider.addTarget(self,
action: Selector("sliderAction"),
forControlEvents: UIControlEvents.ValueChanged)
self.slider.minimumValue = minimumFontSize
self.slider.maximumValue = maximumFontSize
view.addSubview(self.slider)
}
func createLabel(origin: CGPoint, size: CGSize) {
let labelOrigin = CGPoint(x: origin.x, y: origin.y + size.height)
let frame = CGRect(origin: labelOrigin, size: size)
self.label = UILabel(frame: frame)
self.label.textAlignment = NSTextAlignment.Center
view.addSubview(self.label)
}
func sliderAction() {
let fontSize = CGFloat(self.slider.value)
self.label.font = UIFont.systemFontOfSize(fontSize)
self.label.text = "\(Int(fontSize))"
}
}
In case you're using Storyboards:
Add UISlider and UILabel to your View Controller Scene on the Storyboard
Insert #IBOutlets for each control (Ctrl+Drag from the control on the Storyboard to code, choose Outlet from Connection list)
Insert #IBAction for slider's Value Changed event (Ctrl+Drag from the slider control on the Storyboard to code, choose Action from Connection list)
You may end up with something like:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var slider: UISlider!
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.slider.minimumValue = 16
self.slider.maximumValue = 48
self.sliderAction()
}
#IBAction func sliderValueChangedAction(sender: UISlider) {
self.sliderAction()
}
private func sliderAction() {
let fontSize = CGFloat(self.slider.value)
self.label.font = UIFont.systemFontOfSize(fontSize)
self.label.text = "\(Int(fontSize))"
}
}

Resources