I am using Instructions for app walk-through.
Trying to adjust skip alignment since its overlaps the UIButton at view point, as shown in below image.
How to adjust the skip to bottom-center of screen?
CocoaPods: https://cocoapods.org/pods/Instructions
Here is code.
func coachMarkSetup(){
self.coachMarksController.dataSource = self
let skipView = CoachMarkSkipDefaultView()
skipView.titleLabel?.font = UIFont(font: Font.interMedium, size: 14)
skipView.setTitle("Skip", for: .normal)
skipView.layer.cornerRadius = 17
skipView.titleLabel?.layer.cornerRadius = 17
skipView.titleLabel?.textColor = UIColor.init(named: ColorPalette.gray700Color)
skipView.backgroundColor = UIColor.init(named: ColorPalette.gray300Color)
skipView.layer.backgroundColor = UIColor(named: ColorPalette.gray300Color)?.cgColor
self.coachMarksController.overlay.backgroundColor = UIColor.init(named: ColorPalette.grayOpacity) ?? .lightGray
self.coachMarksController.skipView = skipView
self.coachMarksController.skipView?.backgroundColor = UIColor.init(named: ColorPalette.gray300Color)
self.coachMarksController.skipView?.translatesAutoresizingMaskIntoConstraints = false
}
Related
I'm using NSMutableAttributedString to setup text style. When I set .minimumLineHeight, it centre text in line to the bottom of line. I would like to customise somehow this alignment to centre text in line vertically.
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.minimumLineHeight = fontLineHeight // 24 for example
attributedText.addAttribute(.paragraphStyle, value: paragraphStyle, range: fullRange)
I want to get such result:
The problem with providing a lineHeight is that you override the default height-calculation-behaviour with a hardcoded value. Even if you've provided the font's line height as the value, it can vary dynamically based on provided content and it's best to leave this to auto layout (Refer https://stackoverflow.com/a/33278748/9293498)
Auto-layout has a solution for these issues most of the time. All you need is a proper constraint setup for your label (and lineSpacing in your scenario) which can enable it to scale automatically based on provided text with just-enough space required. Both NSAttributedString and String values should work
Here's a code sample I've written trying to simulate your requirement:
Views:
private let termsAndConditionsContainer: UIStackView = {
let container = UIStackView()
container.backgroundColor = .clear
container.spacing = 16
container.axis = .vertical
container.alignment = .leading
container.distribution = .fill
container.translatesAutoresizingMaskIntoConstraints = false
return container
}()
private let dataAgreementButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(), for: .normal)
button.layer.borderColor = UIColor.gray.cgColor
button.layer.borderWidth = 0.5
button.layer.cornerRadius = 16
return button
}()
private let dataAgreementLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 17, weight: .medium)
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let tosAgreementButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(), for: .normal)
button.layer.borderColor = UIColor.gray.cgColor
button.layer.borderWidth = 0.5
button.layer.cornerRadius = 16
return button
}()
private let tosAgreementLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 17, weight: .medium)
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
Functions:
private func attributedString(with text: String) -> NSAttributedString {
//Leave it to auto-layout to determine the line height
let attributedString = NSMutableAttributedString(string: text)
let style = NSMutableParagraphStyle()
style.lineSpacing = 8 // I've just declared the spacing between lines
attributedString.addAttribute(.paragraphStyle, value: style, range: NSRange(location: 0, length: attributedString.length))
return attributedString
}
private func generateRowContainer() -> UIStackView {
let container = UIStackView()
container.backgroundColor = .clear
container.spacing = 16
container.axis = .horizontal
container.alignment = .center
container.distribution = .fill
container.layer.borderWidth = 0.5
container.layer.borderColor = UIColor.green.cgColor
container.translatesAutoresizingMaskIntoConstraints = false
return container
}
And here's my constraint setup as I add the above views in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
let dataAgreementContainer = generateRowContainer()
dataAgreementContainer.addArrangedSubview(dataAgreementButton)
dataAgreementLabel.attributedText = attributedString(with: "I agree with the Information note regarding personal data processing")
dataAgreementContainer.addArrangedSubview(dataAgreementLabel)
termsAndConditionsContainer.addArrangedSubview(dataAgreementContainer)
let tosAgreementContainer = generateRowContainer()
tosAgreementContainer.addArrangedSubview(tosAgreementButton)
tosAgreementLabel.attributedText = attributedString(with: "I agree with terms and conditions")
tosAgreementContainer.addArrangedSubview(tosAgreementLabel)
termsAndConditionsContainer.addArrangedSubview(tosAgreementContainer)
view.addSubview(termsAndConditionsContainer)
NSLayoutConstraint.activate([
dataAgreementButton.widthAnchor.constraint(equalToConstant: 32),
dataAgreementButton.heightAnchor.constraint(equalToConstant: 32),
tosAgreementButton.widthAnchor.constraint(equalToConstant: 32),
tosAgreementButton.heightAnchor.constraint(equalToConstant: 32),
termsAndConditionsContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 32),
termsAndConditionsContainer.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -32),
termsAndConditionsContainer.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
I got the below output:
In the above example, I've used a horizontal stack view to maintain the alignment of text and radio button, which seems efficient to me for your requirement. But the point is, as long as your label is in a properly constrained environment, you don't have the need to manually specify any form of its height.
I'm trying to make view like this:
Everything works fine, but when I put image from API to that UIImageView, this happens:
UIImageView is stretching even with some Hugging Priority and Compression priority
Code for View:
let scrollView = UIScrollView()
let contentView = UIView()
lazy var posterImage = UIImageView().then {
$0.contentMode = .scaleAspectFit
$0.image = UIImage(named: "img_placeholder") // placeholder image
$0.backgroundColor = .orange
$0.setContentHuggingPriority(.required, for: .horizontal)
}
lazy var titleLabel = UILabel().then {
$0.textColor = .white
$0.textAlignment = .left
$0.font = UIFont.systemFont(ofSize: 25, weight: .medium)
$0.numberOfLines = 0
$0.minimumScaleFactor = 10
$0.setContentHuggingPriority(.required, for: .vertical)
}
lazy var taglineLabel = UILabel().then {
$0.numberOfLines = 0
$0.textColor = .lightGray
$0.textAlignment = .left
$0.font = UIFont.systemFont(ofSize: 15, weight: .regular)
}
lazy var runtimeIconLabel = IconLabel().then {
$0.icon.image = UIImage(systemName: "clock")
}
lazy var ratingIconLabel = IconLabel().then {
$0.icon.image = UIImage(systemName: "star.fill")
$0.icon.tintColor = .orange
}
lazy var iconLabels = UIStackView().then {
$0.addArrangedSubview(runtimeIconLabel)
$0.addArrangedSubview(ratingIconLabel)
$0.axis = .horizontal
$0.distribution = .fill
$0.alignment = .leading
$0.spacing = 5
}
lazy var mainInfoLabelStack = UIStackView().then {
$0.addArrangedSubview(titleLabel)
$0.addArrangedSubview(taglineLabel)
$0.addArrangedSubview(UIView())
$0.addArrangedSubview(iconLabels)
$0.axis = .vertical
$0.distribution = .fill
$0.alignment = .leading
$0.spacing = 5
}
lazy var mainInfoStackView = UIStackView().then {
$0.addArrangedSubview(posterImage)
$0.addArrangedSubview(mainInfoLabelStack)
$0.axis = .horizontal
$0.distribution = .fill
$0.alignment = .fill
$0.spacing = 10
$0.isLayoutMarginsRelativeArrangement = true
$0.layoutMargins = UIEdgeInsets.detailViewComponentInset
posterImage.setContentHuggingPriority(.required, for: .horizontal)
mainInfoLabelStack.setContentHuggingPriority(.defaultLow, for: .horizontal)
}
Adding Constraints:
self.view.addSubview(scrollView)
scrollView.addSubview(contentView)
scrollView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
contentView.snp.makeConstraints { make in
make.edges.equalToSuperview()
make.width.equalToSuperview()
}
contentView.addSubview(mainInfoStackView)
mainInfoStackView.snp.makeConstraints { make in
make.top.left.right.equalToSuperview()
make.height.equalTo(self.view.snp.width).multipliedBy(0.45)
}
I want to remove unintended margin of UIImageView
You must set image contentMode to "scaleAspectFill" for the "posterImage" because of dimension:
lazy var posterImage = UIImageView().then {
$0.contentMode = .scaleAspectFill
$0.image = UIImage(named: "img_placeholder") // placeholder image
$0.backgroundColor = .orange
}
remove the below code
$0.setContentHuggingPriority(.required, for: .horizontal)
and set fix width and height constraint for the image
A UIImageView has no intrinsic size, until an image has been set. At that point, if you haven't given constraint conditions to control it, UIKit will change its size based on the new image.
You probably want something like this:
posterImage.snp.makeConstraints { make in
make.width.equalTo(posterImage.snp.height).multipliedBy(0.75)
}
to give the image view a 4:3 ratio.
Adjust that .multipliedBy value to suit your design.
Edit
Here's the result...
Initially, posterImage has a "placeholder" image:
then we set its image to this one:
Okay, so I have a tableView with a textField where when the user taps the textField within the tableView, the keyboard is presented with a custom InputAccessoryView. It looks like this:
And here is the code to create the custom InputAccessoryView, which I've tried within the cellForRowAt and on textFieldDidBeginEditing (as below) for the tableView (each row performs a different function).
func textFieldDidBeginEditing(_ textField: UITextField) {
print("textFieldDidBeginEditing")
if textField.tag == 1 {
profileDataTextField.addToolbarInputAccessoryView()
}
}
I've created it as an extension from the UITextField:
extension UITextField {
func addToolbarInputAccessoryView() {
let screenWidth = UIScreen.main.bounds.width
// Create Main Container View
let mainContainerView = UIView()
mainContainerView.backgroundColor = .clear
mainContainerView.frame = CGRect(x: 0, y: 0, width: screenWidth, height: 120)
// Create Heading Label
let label = UILabel()
label.textColor = .white
label.font = UIFont(name: "BrandonGrotesque-Bold", size: 20)
label.text = "Enter New Weight"
label.widthAnchor.constraint(equalToConstant: screenWidth).isActive = true
label.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
label.textAlignment = .center
// Create Input Container View
let inputContainerView = UIView()
inputContainerView.backgroundColor = .white
inputContainerView.heightAnchor.constraint(equalToConstant: 80.0).isActive = true
inputContainerView.widthAnchor.constraint(equalToConstant: screenWidth).isActive = true
// Create inputTextField
let inputTextField = UITextField()
inputTextField.translatesAutoresizingMaskIntoConstraints = false
inputTextField.placeholder = "150"
inputTextField.textAlignment = .left
inputTextField.textColor = .darkGray
inputTextField.font = UIFont(name: "BrandonGrotesque-Bold", size: 50)
inputTextField.backgroundColor = .white
inputTextField.layer.cornerRadius = 4
inputTextField.layer.masksToBounds = true
inputTextField.borderStyle = .none
// Create metricTextField
let metricLabel = UILabel()
metricLabel.textColor = .darkGray
metricLabel.font = UIFont(name: "BrandonGrotesque-Bold", size: 18)
metricLabel.text = "lbs"
metricLabel.textAlignment = .left
// Create Done button
let doneButton = UIButton()
doneButton.backgroundColor = .systemIndigo
doneButton.setTitle("Done", for: .normal)
doneButton.titleLabel?.font = UIFont(name: "BrandonGrotesque-Bold", size: 20)
doneButton.cornerRadius = 4
doneButton.translatesAutoresizingMaskIntoConstraints = false
doneButton.addTarget(self, action: #selector(doneTapped), for: .touchUpInside)
// Create cancel button
let cancelButton = UIButton()
cancelButton.backgroundColor = .systemRed
cancelButton.setTitle("Cancel", for: .normal)
cancelButton.titleLabel?.font = UIFont(name: "BrandonGrotesque-Bold", size: 20)
cancelButton.cornerRadius = 4
cancelButton.translatesAutoresizingMaskIntoConstraints = false
cancelButton.addTarget(self, action: #selector(cancelTapped), for: .touchUpInside)
// Main Stack View
let mainStackView = UIStackView()
mainStackView.axis = .vertical
mainStackView.distribution = .fill
mainStackView.alignment = .fill
mainStackView.spacing = 10.0
mainStackView.backgroundColor = .clear
// Toolbar StackView
let toolbarStackView = UIStackView()
toolbarStackView.axis = .horizontal
toolbarStackView.distribution = .fillEqually
toolbarStackView.alignment = .fill
toolbarStackView.spacing = 20.0
toolbarStackView.backgroundColor = .white
// Input Stackview
let inputStackView = UIStackView()
inputStackView.axis = .horizontal
inputStackView.distribution = .equalCentering
inputStackView.alignment = .center
inputStackView.spacing = 5.0
inputStackView.backgroundColor = .white
// Put it all together
mainStackView.addArrangedSubview(label)
inputStackView.addArrangedSubview(inputTextField)
inputStackView.addArrangedSubview(metricLabel)
toolbarStackView.addArrangedSubview(cancelButton)
toolbarStackView.addArrangedSubview(inputStackView)
toolbarStackView.addArrangedSubview(doneButton)
toolbarStackView.translatesAutoresizingMaskIntoConstraints = false
inputContainerView.addSubview(toolbarStackView)
mainStackView.addArrangedSubview(inputContainerView)
mainStackView.translatesAutoresizingMaskIntoConstraints = false
toolbarStackView.leadingAnchor.constraint(equalTo: inputContainerView.leadingAnchor, constant: 15).isActive = true
toolbarStackView.trailingAnchor.constraint(equalTo: inputContainerView.trailingAnchor, constant: -15).isActive = true
toolbarStackView.topAnchor.constraint(equalTo: inputContainerView.topAnchor, constant: 15).isActive = true
toolbarStackView.bottomAnchor.constraint(equalTo: inputContainerView.bottomAnchor, constant: -15).isActive = true
mainContainerView.addSubview(mainStackView)
inputAccessoryView = mainContainerView
}
#objc func cancelTapped() {
self.resignFirstResponder()
}
#objc func doneTapped() {
self.resignFirstResponder()
}
}
The problem is, I don't know how to reference the textField ("150" in the image) within the InputAccessoryView when the keyboard appears to set it as the first responder and not the original textField.
I want the inputs from the keyboard to change the text in the TextField within the InputAccessoryView. Right now the original textField is still the first responder.
I've tried setting inputTextField to becomeFirstResponder upon creation within the function (cellForRowAt), but that's obviously too early, as the keyboard hasn't appeared yet.
I have researched the similar questions/answers, but none of them cover how to reference the textField within the InputAccessoryView--especially when coming from a tableViewCell.
Try calling the becomeFirstResponder asynchronously with a delay to allow the keyboard to initialise:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
textField.becomeFirstResponder()
}
Firstly I support making it a custom view instead of an extension for easy access of the textField
Secondly to access it your current way add a tag to your textfield like this
inputTextField.tag = 33
Finally access the textField like this
profileDataTextField.addToolbarInputAccessoryView()
guard let field = profileDataTextField.inputAccessoryView.viewWithTag(33) else { return }
field.becomeFirstResponder()
I'm struggling a lot trying to change the Corner Radius of a customized Segmented Controller. Does anyone know what the problem might be?
Blessings
lazy var mainSegment: UISegmentedControl = {
let sc = UISegmentedControl(items: items)
sc.translatesAutoresizingMaskIntoConstraints = false
sc.selectedSegmentTintColor = .orange
sc.selectedSegmentIndex = 0
sc.backgroundColor = .white
sc.setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
sc.setTitleTextAttributes([.foregroundColor: UIColor.gray], for: .normal)
sc.layer.cornerRadius = 20
sc.layer.borderWidth = 0.1
sc.layer.borderColor = UIColor.white.cgColor
sc.clipsToBounds = true
sc.layer.masksToBounds = true
sc.addTarget(self, action: #selector(handleSegmentChanges), for: .valueChanged)
return sc
}()
am using XLpagertabstrip in my application .. but i have a problem that the text is bigger than the width and it got cut from both sides .. like image below:
as you can see last tab which is المواجهات المباشرة is not displayed fully..
this is my code:
override func viewDidLoad() {
super.viewDidLoad()
containerView.isScrollEnabled = false
containerView.delegate = self
self.settings.style.buttonBarBackgroundColor = UIColor.clear
self.settings.style.buttonBarItemBackgroundColor = UIColor.clear
self.settings.style.selectedBarBackgroundColor = UIColor.clear
self.settings.style.buttonBarItemFont = .boldSystemFont(ofSize: 7)
self.settings.style.selectedBarHeight = 1.0
self.settings.style.buttonBarMinimumLineSpacing = 0.1
self.settings.style.buttonBarItemTitleColor = UIColor.white
self.settings.style.buttonBarItemsShouldFillAvailableWidth = true
self.settings.style.buttonBarLeftContentInset = 0
self.settings.style.buttonBarRightContentInset = 0
self.settings.style.selectedBarHeight = 1.0
changeCurrentIndexProgressive = { [weak self] (oldCell: ButtonBarViewCell?, newCell: ButtonBarViewCell?, progressPercentage: CGFloat, changeCurrentIndex: Bool, animated: Bool) -> Void in
guard changeCurrentIndex == true else { return }
//oldCell?.label.adjustsFontSizeToFitWidth = true
//newCell?.label.adjustsFontSizeToFitWidth = true
oldCell?.label.textColor = UIColor.white
newCell?.label.textColor = UIColor.white
oldCell?.label.font = UIFont(name: "AJannatLT", size: 14)!
newCell?.label.font = UIFont(name: "AJannatLT", size: 14)
newCell?.label.lineBreakMode = .byCharWrapping
oldCell?.label.lineBreakMode = .byCharWrapping
self?.buttonBarView.selectedBar.backgroundColor = UIColor.white
}
getMatchInfo()
self.navigationController?.navigationBar.topItem?.title = " "
// Do any additional setup after loading the view.
}
but this will only change it's font size if i tabbed it ...
how to solve this? i want it from the start to be fully displayed and fit cell's width ..
but i have a problem that the text is bigger than the width and it got cut from both side
You can try lineBreakMode
label.lineBreakMode = .ByCharWrapping
Read more about LineBreakMode.