XLForm dynamically change section title - ios

I just started using XLForm and faced some problems. I have a section which title I have to change depending on field above it.
So when I select an option, I need the same title for section.
In code I do:
if formRow.tag == "subCategory" {
switch newValue.description {
case lightVehicle:
vehicleSection.hidden = false
mileageRow!.hidden = false
break
case heavyVehicle:
mileageRow!.hidden = true
mileageRow!.value = nil
vehicleTypeRow!.hidden = true
break
case bikes:
mileageRow?.hidden = true
vehicleTypeRow!.hidden = false
break
default:break
}
// Here I set the title
vehicleSection.title = newValue.description
}
So I know that the value is changed, but for displaying it I need smth like reloadFormRow(). Unfortunately there is no such method for sections
I found hacky way to do that is tableView.reloadData(), but in documentation they not recommend do any manipulations directly with tableView itself.

Related

Force RTL direction on specific ViewController

I know I can force the direction of my app using:
[[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
My question is, can I force it only on one specific ViewController?
Sorry for the code in swift, see the last line of code hope it suits yours need,
My understanding is if you want to set it to a specific VC then you have to assign sematic values to the views by using outlets,
enum AppLanguages: String {
case English = "en"
case Thai = "th"
case Arabic = "ar"
case Tamil = "ta"
var sematic : UISemanticContentAttribute {
switch self {
case .English,.Thai,.Tamil:
return .forceLeftToRight
case .Arabic:
return .forceRightToLeft
}
}
}
then
UIView.appearance().semanticContentAttribute = AppLanguages(rawValue: "ar").sematic
or - if you like to change the buttons only or particular UI's only then,
UIButton.appearance().semanticContentAttribute = .forceLeftToRight
The above will change RTF for all uiview throughtout the application,
best practice is use a tableview to design the specific view and then reload it based on language changes it will work.
For your specific views,
self.yourView.semanticContentAttribute = AppLanguages(rawValue: "ar").sematic

How to retrieve value from a row with changed textfield with Eureka form?

I'm trying to retrieve the value of the typed field in a row of an Eureka form (https://eurekacommunity.github.io). I've set up a new textfield with a mask, but when I send it back it returns me empty.
TextRow:
<<< TextRow(Constants.CPF) {
$0.title = Constants.cpf_title
$0.placeholder = Constants.cpf_placeholder
}
.cellSetup { cell, _ in
let tf = JMMaskTextField(frame: cell.textField.frame)
tf.maskString = "000.000.000-00"
cell.textField.removeFromSuperview()
tf.translatesAutoresizingMaskIntoConstraints = false
cell.textField = tf
cell.contentView.addSubview(tf)
}
.cellUpdate { cell, _ in
cell.textField.delegate = self
}
Result:
let values = self.form.values()
print(values[Constants.CPF])
Optional(nil)
Apparently the mask is working properly, but I think I'm forgetting to set something up. Does anyone have any ideas?
If you want to use different UITextField in your row, you should create custom row for that. In this case, you can subclass from TextRow and implement you cell with JMMaskTextField. Just remove default textField and set the new (as you did) doesn't work.

Eureka: Form validation not up-to-date

I have a Eureka form that uses validation rules and .cellUpdate() to reflect the validation status for each form field. Additionally, I want to display the validation status of the whole form (by colouring/enabling an "OK" button). For this purpose I use the valueHasBeenChanged callback function in my FormViewController. I cycle through all rows and test for row.isValid. However, it seems that isValid reflects the status before the value actually is changed.
How can I achieve the intended mechanism in a clean way (that is, not fiddling with global variables or the like)?
The callback is indeed called in RowOf<T>.didSet, but isValid gives the result of validationErrors.isEmpty. The validationErrors list in turn is updated after the row's internal _value has been set, causing the behaviour described in my question. As I understand, it is this way no matter what's the setting in the row's validationOptions.
My remedy is to call row.validate() in my valueHasBeenChanged function to explicitly trigger the validation before I read the row's isValid status. The cost of an additional call of the row's validation rules is negligible
for me.
A simpler way to implement on-click form validation is add the
.cellUpdate { cell, row in
if !row.isValid {
cell.titleLabel?.textColor = .red
}
}
code to each of your rows, use . validatesOnDemand as the validation rule for the row, then call form.validate() in your button action.
For example:
<<< TextRow() { row in
row.title = ""
row.tag = "firstName"
row.add(rule: RuleRequired())
row.validationOptions = .validatesOnDemand
}
.cellUpdate { cell, row in
if !row.isValid {
cell.backgroundColor =.red
cell.titleLabel?.textColor = .red
} else {
cell.backgroundColor = .clear
cell.titleLabel?.textColor = .white
}
}
...
form.validate()

How to switch between two auto-layout constraints?

I have two UI layout constraints that are conflicting with each other by design. Only one of could be active at a time.
In UIViewController's method updateConstraintsIfNeeded, I have the following code which toggles between the two constraints, depending on the state of a data model.
override func updateConstraintsIfNeeded() {
super.updateConstraintsIfNeeded()
if question?.thumbURL != nil {
showAttachmentConstraint.active = true
hideAttachmentConstraint.active = false
} else {
showAttachmentConstraint.active = false
hideAttachmentConstraint.active = true
}
}
This work as intended, but I got this familiar warning in the debug output:
Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. ...
Apparently when the statement showAttachmentConstraint.active = true is executed, it temporarily conflicts with hideAttachmentConstraint which is still active at that time.
Is it possible to make this toggle operation atomic? I'm hoping there is something like beginUpdate and endUpdate in UITableView.
you could change the priority of one of the conflicting constraints to 999 instead of 1000. so you do not even have any problems at design time.
Always first deactivate some constraints and then activate the other constraints:
override func updateConstraintsIfNeeded() {
super.updateConstraintsIfNeeded()
if question?.thumbURL != nil {
hideAttachmentConstraint.active = false
showAttachmentConstraint.active = true
} else {
showAttachmentConstraint.active = false
hideAttachmentConstraint.active = true
}
}

Swift update UILabel with dispatch_async not working

Why doesn't this work?
dispatch_async(dispatch_get_main_queue(), {
self.timeStringLabel.text = "\(self.timeStringSelected)"
println(self.timeStringLabel.text)
})
I'm trying to update a label in Swift but the UI for the label never changes. I keep googling it, but I can't find any responses that don't use dispatch_async. What am I doing wrong?
1st Edit: I was mistaken. I'm not printing the updated text. The text never changes. It always prints out Optional("0") if that helps. The default value is 0 as defined in the Storyboard.
I have tried it with and without dispatch_async without any success. I also tried adding
self.timeStringLabel.setNeedsDisplay()
Immediately after updating the text, but that also doesn't work.
Edit 2: Here's the complete function + UILabel declaration
#IBOutlet weak var timeNumberLabel: UILabel!
#IBAction func timeNumberButtonPressed(sender: UIButton) {
println("Number Selected. Tag \(sender.tag)")
dispatch_async(dispatch_get_main_queue()) {
self.timeNumberOneButton.selected = false
self.timeNumberTwoButton.selected = false
self.timeNumberThreeButton.selected = false
self.timeNumberFourButton.selected = false
if sender.tag == 0{
self.timeNumberSelected = 0
} else if sender.tag == 1 {
self.timeNumberSelected == 5
} else if sender.tag == 2 {
self.timeNumberSelected == 10
} else {
self.timeNumberSelected == 24
}
sender.selected = true
self.timeNumberLabel.text = "\(self.timeNumberSelected)"
self.timeNumberLabel.setNeedsDisplay()
println(self.timeNumberLabel.text)
}
}
The label is clearly visible as shown in this picture. I didn't think it would be this hard to implement, but I was very wrong. I'm willing to bet it's something really simple that I'm missing.
Try adding the line
self.timeStringLabel.setNeedsDisplay()
(after the label change)
Because the code is run asynchronously, the interface-updating methods may miss the change and not display it (especially if a time-consuming bit of code occurs before the label change). Adding this code forces the interface to check for and display any changes it may have missed.
This should be used after any asynchronous task that changes the interface, as the task's running may overlap with the interface methods, resulting in a missed change.
*Thanks to the iOS Development Journal

Resources