I have a label with a single character that I wish to be bigger than the UIView that it's a subview of. However, I need to hide the overflowing parts of the character.
For an example, this is the result I'm trying to achieve:
Where the character/Icon is the tags in lighter green in the background
Like the above example I'm using the font called "fontawesome" and their icon set. However in Swift I havn't been able to find any options to hide the overflowing parts.
Here's the current code:
var actionBox = UIView()
var actionLabel = UILabel()
var actionIcon = UILabel()
// #actionBox
actionBox.translatesAutoresizingMaskIntoConstraints = false
actionBox.backgroundColor = UIColor.formulaGreenColor()
cellView.addSubview(actionBox)
actionIcon.translatesAutoresizingMaskIntoConstraints = false
actionIcon.font = UIFont(name: "fontawesome", size: 80)
actionIcon.text = ""
actionIcon.textColor = UIColor.colorWithHex("#13E6A7")
actionBox.addSubview(actionIcon)
I know I can technically make another 2 UIViews, with a background color, and layer those on top. But that's not exactly an elegant solution.
So how can I hide the rest of the label, that's overflowing it's superView?
Any help would be greatly appreciated!
You are searching for clipsToBounds property:
view.clipsToBounds = true
Where view is your container view.
Related
I tried virtually every solution I could find for changing the background color of a UISearchController SearchBar, but none of them produced the correct color as the background. Every solution produces a somewhat darker color, and as demonstrated in the image below, white seems more pale / off-white.
How can I make the search bar a true white color?
One of the more recent "solutions" that results in white being pale is below:
let searchController = UISearchController()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.searchController = searchController
let textFieldInsideSearchBar = searchController.searchBar.value(forKey: "searchField") as? UITextField
textFieldInsideSearchBar?.backgroundColor = UIColor.white
}
The default border style is being impacted by the navigationItem. If you remove the border style and manually set the corner radius, it should display as white. White seems to be the only color I ran into being affected by this.
Change:
textFieldInsideSearchBar?.backgroundColor = UIColor.white
To:
textFieldInsideSearchBar?.borderStyle = .none
textFieldInsideSearchBar?.cornerRadius = 10
textFieldInsideSearchBar?.backgroundColor = .white
When I put the search bar in a table header, your code above (without altering the border/radius) worked without issue, but when I tried to embed it into a navigation bar item, I ran into your problem.
(Xcode 11, Swift)
Being a newbie to iOS and Autolayout, I'm struggling with implementing a fairly simple (IMHO) view which displays a [vertical] list of items. The only problem is that items are decided dynamically and each of them could be either text or image (where either of those could be fairly large so scrolling would be required). WebView is not an option, so it has to be implemented natively.
This is how I understand the process:
Make in IB a UIScrollView and size it to the size of the outer frame.
Make a container view as a subview of UIScrollView (again, in IB) and size it the same.
Set constraint on equal width of both
At runtime, populate container view with UILabels/UIImageViews and also set constraints programmatically to ensure proper layout.
"Tell" scrollview about the subview height in order to make it manage the scrolling thereof.
Is this the right approach? It doesn't seem to work for me (for a toy example of dynamically adding a very tall image to a container view - I cannot get the scrolling to work). What would be the proper way to do the last step in the process above - just force the contentSize of the scrollview to the size of the populated container view (it doesn't seem to work for me). Any help would be appreciated.
When adding multiple elements to a scroll view at run-time, you may find it much easier to use a UIStackView... when setup properly, it will automatically grow in height with each added object.
As a simple example...
1) Start by adding a UIScrollView (I gave it a blue background to make it easier to see). Constrain it to Zero on all 4 sides:
Note that we see the "red circle" indicating missing / conflicting constraints. Ignore that for now.
2) Add a UIView as a "content view" to the scroll view (I gave it a systemYellow background to make it easier to see). Constrain it to Zero on all 4 sides to the Content Layout Guide -- this will (eventually) define the scroll view's content size. Also constrain it equal width and equal height to the Frame Layout Guide:
Important Step: Select the Height constraint, and in the Size Inspector pane select the Placeholder - Remove at build time checkbox. This will satisfy auto-layout in IB during design time, but will allow the height of that view to shrink / grow as necessary.
3) Add a Vertical UIStackView to the "content view". Constrain it to Zero on all 4 sides. Configure its properties to Fill / Fill / 8 (as shown below):
4) Add an #IBOutlet connection to the stack view in your view controller class. Now, at run-time, as you add UI elements to the stack view, all of your "scrollability" will be handled by auto-layout.
Here is an example class:
class DynaScrollViewController: UIViewController {
#IBOutlet var theStackView: UIStackView!
override func viewDidLoad() {
super.viewDidLoad()
// local var so we can reuse it
var theLabel = UILabel()
var theImageView = UIImageView()
// create a new label
theLabel = UILabel()
// this gets set to false when the label is added to a stack view,
// but good to get in the habit of setting it
theLabel.translatesAutoresizingMaskIntoConstraints = false
// multi-line
theLabel.numberOfLines = 0
// cyan background to make it easy to see
theLabel.backgroundColor = .cyan
// add 9 lines of text to the label
theLabel.text = (1...9).map({ "Line \($0)" }).joined(separator: "\n")
// add it to the stack view
theStackView.addArrangedSubview(theLabel)
// add another label
theLabel = UILabel()
// multi-line
theLabel.numberOfLines = 0
// yellow background to make it easy to see
theLabel.backgroundColor = .yellow
// add 5 lines of text to the label
theLabel.text = (1...5).map({ "Line \($0)" }).joined(separator: "\n")
// add it to the stack view
theStackView.addArrangedSubview(theLabel)
// create a new UIImageView
theImageView = UIImageView()
// this gets set to false when the label is added to a stack view,
// but good to get in the habit of setting it
theImageView.translatesAutoresizingMaskIntoConstraints = false
// load an image for it - I have one named background
if let img = UIImage(named: "background") {
theImageView.image = img
}
// let's give the image view a 4:3 width:height ratio
theImageView.widthAnchor.constraint(equalTo: theImageView.heightAnchor, multiplier: 4.0/3.0).isActive = true
// add it to the stack view
theStackView.addArrangedSubview(theImageView)
// add another label
theLabel = UILabel()
// multi-line
theLabel.numberOfLines = 0
// yellow background to make it easy to see
theLabel.backgroundColor = .green
// add 2 lines of text to the label
theLabel.text = (1...2).map({ "Line \($0)" }).joined(separator: "\n")
// add it to the stack view
theStackView.addArrangedSubview(theLabel)
// add another UIImageView
theImageView = UIImageView()
// this gets set to false when the label is added to a stack view,
// but good to get in the habit of setting it
theImageView.translatesAutoresizingMaskIntoConstraints = false
// load a different image for it - I have one named AquariumBG
if let img = UIImage(named: "AquariumBG") {
theImageView.image = img
}
// let's give this image view a 1:1 width:height ratio
theImageView.heightAnchor.constraint(equalTo: theImageView.widthAnchor, multiplier: 1.0).isActive = true
// add it to the stack view
theStackView.addArrangedSubview(theImageView)
}
}
If the steps have been followed, you should get this output:
and, after scrolling to the bottom:
Alignment constraints (leading/trailing/top/bottom)
The alignment constraint between Scroll View and Content View defines the scrollable range of the content. For example,
If scrollView.bottom = contentView.bottom, it means Scroll View is
scrollable to the bottom of Content View.
If scrollView.bottom = contentView.bottom + 100, the scrollable
bottom end of Scroll View will exceed the end of Content View by 100
points.
If scrollView.bottom = contentView.bottom — 100, the bottom of
Content View will not be reached even the scrollView is scrolled to
the bottom end.
That is, the (bottom) anchor on Scroll View indicates the (bottom) edge of the outer frame, i.e., the visible part of Content View; the (bottom) anchor on Content View refers to the edge of the actual content, which will be hidden if not scrolled to.
Unlike normal use cases, alignment constraints between Scroll View and Content View have nothing to do with the actual size of Content View. They affect only “scrollable range of content view” but NOT “actual content size”. The actual size of Content View must be additionally defined.
Size constraints (width/height)
To actually size Content View, we may set the size of Content View to a specific length, like width/height of 500. If the width/height exceeds the width/height of Scroll View, there will be a scrollbar for users to scroll.
However, a more common case will be, we want Content View to have the same width (or height) as Scroll View. In this case, we will have
contentView.width = scrollView.width
The width of Content View refers to the actual full width of content. On the other hand, the width of Scroll View refers to the outer container frame width of Scroll View. Of course, it doesn’t have to be the same width, but can be other forms like a * scrollView.width + b.
And if we have Content View higher (or wider) than Scroll View, a scrollbar appears.
Content View can not only be a single view, but also multiple views, as long as they are appropriately constrained using alignment and size constraints to Scroll View.
For details, you may follow this article: Link.
I could find a good solution to make a window with rounded corners
https://github.com/lukakerr/NSWindowStyles
Section: 6. Vibrant background with border radius and no titlebar
let visualEffect = NSVisualEffectView()
visualEffect.translatesAutoresizingMaskIntoConstraints = false
visualEffect.material = .dark
visualEffect.state = .active
visualEffect.wantsLayer = true
visualEffect.layer?.cornerRadius = 16.0
window?.titleVisibility = .hidden
window?.styleMask.remove(.titled)
window?.backgroundColor = .clear
window?.isMovableByWindowBackground = true
window?.contentView?.addSubview(visualEffect)
guard let constraints = window?.contentView else {
return
}
visualEffect.leadingAnchor.constraint(equalTo: constraints.leadingAnchor).isActive = true
visualEffect.trailingAnchor.constraint(equalTo: constraints.trailingAnchor).isActive = true
visualEffect.topAnchor.constraint(equalTo: constraints.topAnchor).isActive = true
visualEffect.bottomAnchor.constraint(equalTo: constraints.bottomAnchor).isActive = true
I find that it only works if I put it in the viewWillAppear or in the viewDidLoad with a delay. In any case, when I get the border-radius and the vibrant background I cannot see anything that is in the window, for instance, a simple label with the text test. (I tried to put that text on the storyboard or by code)
#IBOutlet weak var label1: NSTextField!
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0){
self.label1.stringValue = "test text"
}
How to make a label visible with this code?
(or as second option, how to make a window with round corners, no bar, background semi-transparent or vibrant and a label non-transparent on top or inside?)
(I know how to make the title bar transparent and remove the buttons and title. But that is not a good solution for what I need because the bar is still there and creates a space that makes problems)
The problem with the label is you're adding NSVisualEffectView above it. You could instead try adding it below:
view.addSubview(visualEffect, positioned: .below, relativeTo: label1)
But be careful you add it only once: viewWillAppear can be called multiple times.
I am trying to display a basic UITextView programmatically. The problem is, if I want to display a UILabel with the same constraints and settings, it's all fine, I can have it displayed. However, if I change it to a UITextView, it just disappears. I created an empty project, just to check it, but still, no avail, just does not display.
Here's my code that works fine for a UILabel:
view = UIView()
view.backgroundColor = .systemBackground
explanationView = UILabel()
explanationView.layer.zPosition = 1
explanationView.translatesAutoresizingMaskIntoConstraints = false
explanationView.numberOfLines = 10
view.addSubview(explanationView)
NSLayoutConstraint.activate([
explanationView.centerXAnchor.constraint(equalTo: view.layoutMarginsGuide.centerXAnchor),
explanationView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
explanationView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
explanationView.bottomAnchor.constraint(greaterThanOrEqualTo: view.layoutMarginsGuide.bottomAnchor, constant: -20)
])
I am using layer.zPosition to display it over a UIImageView. I also add .isScrollEnabled for the text view. I also tried creating the UITextView via a computed property, but did not have any luck either.
Any help is appreciated.
Edit: Below is the code that I use for the text view.
explanationView = UITextView()
explanationView.layer.zPosition = 1
explanationView.translatesAutoresizingMaskIntoConstraints = false
explanationView.isScrollEnabled = true
view.addSubview(explanationView)
I'm currently using a stackView that contains a few vertically aligned elements. I'm doing everything in code.
I've marked every stack view's subview. Here's a screenshot:
This is the code for the stackview:
func setUpVerticalLayoutStackView() {
stackViewForVerticalLayout = UIStackView(arrangedSubviews: [viewTitleButton, stackViewForTheTwoPersons, owedButton, amountTextField, doneButton])
stackViewForVerticalLayout.axis = .vertical
stackViewForVerticalLayout.distribution = .equalCentering
stackViewForVerticalLayout.alignment = .center
stackViewForVerticalLayout.spacing = 20
stackViewForVerticalLayout.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(stackViewForVerticalLayout)
}
My question is: why does the textfield occupy so much space? Can I reduce it somehow?
Don't mind the "r" at the center of the view, it's just something I mistakenly added in an image editor.
Change stackViewForVerticalLayout.distribution to .equalSpacing or .fillEqually depending on what you want. This will reduce this size of the field