Scroll View dynamic height issue - ios

In my application I have Scroll View with dynamic height.
Inside it there is one Text View and one Table View - both with dynamic height and scrolling disabled.
These two elements are presented only once per time, so if Text View is visible, then Table View is not.
My issue is that after the screen loaded Scroll View height doesn't get calculated correctly and when you switch for the first time to Table View - it get's covered by background UIView.
Here's how it looks like:
First image - screen just opened, initial position.
Second Image - switched to table view, where it got covered by bg view.
Here's my code:
override func viewDidLoad() {
super.viewDidLoad()
output?.viewIsReady()
setSpeakerData()
contentTableView.register(UINib(nibName: "SpeakerEventsTableViewCell", bundle: nil), forCellReuseIdentifier: "speakerEventsTableViewCell")
}
override func viewWillAppear(_ animated: Bool) {
showSpeakerInfo()
}
func showSpeakerInfo() {
aboutSpeakerTextView.isHidden = false
contentTableView.isHidden = true
aboutSpeakerTextView.sizeToFit()
aboutSpeakerView.backgroundColor = blueColor
eventsView.backgroundColor = UIColor.clear
contentTableViewHeight.constant = aboutSpeakerTextView.frame.height
}
func showSpeakerEvents() {
aboutSpeakerTextView.isHidden = true
contentTableView.isHidden = false
aboutSpeakerView.backgroundColor = UIColor.clear
eventsView.backgroundColor = blueColor
contentTableViewHeight.constant = contentTableView.contentSize.height
contentTableView.reloadData()
}
Strange thing is that when you switch between tabs for several times - everything starts to work properly and Table View doesn't get covered by background UIView.
Would be grateful for any help! Thanks in advance!

Further discovery showed that this bug appears only when text view had 1 lines of text. When it had 2+ lines - it disappeared. I don't know if it's Xcode, Swift or me that led to this)
So, to overcome this bug I've added one line of clear text to my original text received from server and it worked as it should.
This is not a recommended solution, but since it is working - why not.
Here's how my code looks right now:
func setSpeakerData() {
let originalTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(red: 0.41, green: 0.43, blue: 0.51, alpha: 1.0),
NSAttributedString.Key.font: UIFont(name: "Roboto-Light", size: 14.0) as Any]
let dummyTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.clear,
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 15)]
let partOne = NSMutableAttributedString(string: speaker[0].speakerDetailedText, attributes: originalTextAttributes)
let partTwo = NSMutableAttributedString(string: randomText, attributes: dummyTextAttributes)
let combination = NSMutableAttributedString()
combination.append(partOne)
combination.append(partTwo)
speakerImageView.kf.setImage(with: URL(string: speaker[0].speakerImage), placeholder: UIImage(named: "PlaceholderImage"))
speakerNameLabel.text = speaker[0].speakerName
speakerPositionLabel.text = speaker[0].speakerPosition
aboutSpeakerTextView.attributedText = combination
}

Related

Change font of prompt in UINavigationController

can someone help me out in changing font, size and color in prompt string on my NavigationController?
In the attachment, I want to modify "Consulenze" string.
Thank you everybody
Edit: I already tried the solution found here but no results.
You can try following ways:
1) In viewDidLoad of your ViewController add this lines:
self.navigationController?.navigationBar.tintColor = UIColor.white
let navigationTitleFont = UIFont(name: "Avenir", size: 20)!
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.font: navigationTitleFont]
2) You can create completely custom nav bar, just add UIView to the top your view and add all necessary elements - buttons, labels, etc.
Simply add this code in your ViewController. You can change both the Prompt text and color by using this code -
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
for view in self.navigationController?.navigationBar.subviews ?? [] {
let subviews = view.subviews
if subviews.count > 0, let label = subviews[0] as? UILabel {
label.textColor = UIColor.red
label.font = UIFont.systemFont(ofSize: 30)
}
}
}
}
OUTPUT -
Additional -

Multiple lines for large titles in navigation bars in iOS 11

Is it possible to have the new large titles for navigation bars in iOS 11 show multiple lines? The App Store app does this but I can't find anything in the current documentation to do this. The standard behavior just shows one line with ellipsis if it's too long.
Add following code into viewWillAppear:
navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationItem.largeTitleDisplayMode = .automatic
self.title = "Hello big text, For navigation large style bar"
navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black, NSAttributedStringKey.font : UIFont.preferredFont(forTextStyle: .largeTitle)]
var count = 0
for item in(self.navigationController?.navigationBar.subviews)! {
for sub in item.subviews{
if sub is UILabel{
if count == 1 {
break;
}
let titleLab :UILabel = sub as! UILabel
titleLab.numberOfLines = 0
titleLab.text = self.title
titleLab.lineBreakMode = .byWordWrapping
count = count + 1
}
}
}
self.navigationController?.navigationBar.layoutSubviews()
self.navigationController?.navigationBar.layoutIfNeeded()
Facing issue with back button will update soon..
There is a way to do this simply by using a non-public API. Use at your own risk:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
title = "Thunderbox Entertaiment"
navigationItem.enableMultilineTitle()
}
}
extension UINavigationItem {
func enableMultilineTitle() {
setValue(true, forKey: "__largeTitleTwoLineMode")
}
}
Result:

UINavigationBar : Add SearchBar as TitleView

I want to add uisearchbar in place of title of controller.
I am facing 2 problems currently.
1)
I do not know from where this gray background is coming. Please check this picture.
2) I need this searchbar in other inner screens also. But when I push another controller this searchbar is removed.
Here is my code :
// Seachbar Container View
let searchBarContainer = ERView(frame: CGRectMake(0,0,280,44))
searchBarContainer.autoresizingMask = [.FlexibleWidth]
searchBarContainer.backgroundColor = UIColor.clearColor()
// Search Bar
let searchBar = ERSearchBar(frame: searchBarContainer.bounds)
searchBarContainer.addSubview(searchBar)
// Add View as Title View in Navigation Bar
self.navigationController!.navigationBar.topItem?.titleView = searchBarContainer
Here is Code of my UISearchBar Class
func commonInit() -> Void {
// Update UI
if let searchField = self.valueForKey("searchField") as? UITextField{
// To change background color
searchField.backgroundColor = UIColor.appNavigationBarDarkRedColor()
// Tint Color
if let leftViewRef = searchField.leftView {
leftViewRef.tintColor = UIColor.whiteColor()
}else if let imgLeftView = searchField.leftView as? UIImageView{
imgLeftView.tintColor = UIColor.whiteColor()
}
// Font Color
searchField.font = UIFont.robotoRegularFont(WithSize: 14.0)
// Text Color
searchField.textColor = UIColor.whiteColor()
// PlaceHolder Attributes
searchField.attributedPlaceholder = NSAttributedString(string: "Search", attributes: [NSForegroundColorAttributeName:UIColor.whiteColor()])
}
self.setImage(UIImage(named: "ic_search_white"), forSearchBarIcon: UISearchBarIcon.Search, state: UIControlState.Normal)
// To change placeholder text color
}
Please someone help me here.
For 1) Set the searchBarStyle property to minimal. This will provides no default background color in UIsearchBar.
2)I'm not quite sure what'd you mean by "inner screen". But if what you want is a Search Bar that can work across different view controllers, UISearchController is the one you're looking for.
You can fine the Apple sample code here

loading custom appearance values

I would like to know in which function e.g viewDidLoad etc.. would be the best approach to load custom view properties like image border heights, color, all appearance.
For example I add custom values like these in cellForRowAtIndexPath which I think is not best way to do it:
// corner radius
cell.feedImageView.layer.cornerRadius = 10
// border
cell.feedImageView.layer.borderWidth = 2.0
cell.feedImageView.layer.borderColor = UIColor.black.cgColor
cell.feedImageView.layer.masksToBounds = true
And these navigationBar appearance I load in viewDidLoad and i use it in many views:
navigationController?.navigationBar.barTintColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.5)
self.navigationItem.leftBarButtonItem = nil
navigationController?.navigationBar.isTranslucent = true
let fontDictionary = [ NSForegroundColorAttributeName:UIColor.white ]
self.navigationController?.navigationBar.titleTextAttributes = fontDictionary
self.navigationController?.navigationBar.tintColor = UIColor(red: 0.184, green: 0.996, blue: 0.855, alpha: 1.00)
So the question again, where should I load appearance values? I ask it because right now I am in situation where my image border is loading before image etc..
There are so many functions like viewDidLoadAppearance(), ViewDidload(). I've read many questions where they ask what is difference between them but I still do not know where is best to load appearance.
You have basically 3 different options.
1) You could get or set those values in the viewDidAppear() func, after they have been completely instantiated.
2) You could get or set them in the vieDidLayoutSubviews() function and set a bool to check if your task has been called.
var didConfigureUI = false
func viewDidLayoutSubviews() {
if !didConfigureUI {
didConfigureUI = true
updateUI()
}
}
3) You could get or set them in the viewDidLoad using layoutIfNeeded():
override func viewDidLoad() {
super.viewDidLoad()
xy.view.layoutIfNeeded() // <- This will update your initial view frames
updateUI()
}
And your func to do whatever:
func updateUI() {
//f.e feedImageView.layer.masksToBounds = true
}
And to do it in your cellForRowAtIndexPath, you would do something like this, using the layoutIfNeeded() as well.
cellForRowAtIndexPath {
let cell = tableView.blahblahcell
updateUICell(cell.feedImageView)
}
func updateUICell(imageView: UIImageView) {
imageView.layoutIfNeeded()
imageView.layer.cornerRadius = 10
imageView.layer.borderWidth = 2.0
imageView.layer.borderColor = UIColor.black.cgColor
imageView.layer.masksToBounds = true
}
And to answer the last question about the lifecircle:
The circle is:
init
UIViewController awakeFromNib
loadView // your pictureImageView is loaded here
UIView awakeFromNib
UIViewController viewDidLoad
viewWillAppear
viewDidAppear // the properties of your pictureImageView are available here

Trigger an event (tableview reload) whenever a text is in a certain position of a textView in iOS

I just started with iOS programming and I could not find anywhere an answer about this.
I have a Textview, containing a large text divided in paragraphs.
I would like to trigger the reload of a Tableview whenever each paragraph reaches the middle of the TextView.
How could I do it?
Here is the code I wrote so far:
#IBOutlet weak var testo: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
if databaseDB.open() {
// Here I definethe string attributes
var style = NSMutableParagraphStyle()
style.lineSpacing = 15
let font = UIFont(name: "Georgia", size: 18.0) ?? UIFont.systemFontOfSize(18.0)
let textFont = [NSFontAttributeName:font, NSParagraphStyleAttributeName : style]
let fontSuper = UIFont(name: "Georgia-Italic", size: 13.0) ?? UIFont.systemFontOfSize(13.0)
let superFont = [NSFontAttributeName:fontSuper, NSBaselineOffsetAttributeName:6]
// and here the variables
let mainText = NSMutableAttributedString()
var paragraphId : String = ""
// I load the text from a table in the database
let querySQL = "SELECT id, versetext FROM table1"
let results:FMResultSet? = databaseDB.executeQuery(querySQL, withArgumentsInArray: nil)
while results!.next(){
paragraphId = results!.stringForColumn("id")
// I add some other information from another table (here goes also other code, but I have skipped it for simplicity)
let queryDescrSQL = "SELECT paragraph FROM table2 WHERE id = \(paragraphId)"
let paragraphResults:FMResultSet? = databaseDB.executeQuery(queryDescrSQL, withArgumentsInArray: nil)
if paragraphResults?.next() == true {
// here I add the attributes to the text to be shown
let numberParagraph = paragraphResults!.stringForColumn("paragraph")
let paragraphNumber = NSAttributedString(string: numberParagraph, attributes:superFont)
mainText.appendAttributedString(paragraphNumber)
let textParagraph = results!.stringForColumn("versetext")+" "
let paragraphText = NSAttributedString(string: textParagraph, attributes:textFont)
mainText.appendAttributedString(paragraphText)
}
}
databaseDB.close()
// and finally everything is loaded on the TextView
testo.attributedText = mainText
}
}
// I'm letting out the code for the TableView, as it is probably not relevant for the matter
I was thinking of adding some other attribute to paragraphNumber, something like here, but I haven't been able to find how to do it.
Thanks in advance,
Silvo
It's not clear how your paragraphs are divided up (is each in its own UITextView, or do they all form one large text view), but the basics of this are that you need to reload a table view when the scroll view reaches a certain scrolled position.
UITableView has a method reloadData, so call this when your scroll view is at the position.
Scrolling a scroll view just means you are modifying its contentOffset, and the scroll view sends its delegate a message every time the content offset changes. Make your controller the delegate of the scroll view, and implement the scrollViewDidScroll(_:) delegate method. In here, check the current content offset, and if it's at the value you're looking for, reload the table view:
class MyViewController: UIViewController, UIScrollViewDelegate {
// var scrollView = ...
// var tableView = ...
override viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
func scrollViewDidScroll(scrollView: UIScrollView) {
// var scrollThreshold = (calculate some scroll threshold based on your paragraph text)
if scrollView.contentOffset.y > scrollThreshold {
tableView.reloadData()
}
}
}

Resources