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
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)
}
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
}
}
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.
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
}
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))"
}
}