CorePlot legend displays but no names are shown - core-plot

When my bar chart displays I see an area for the legend as it's showing the little colored squares for each plot, but there's no text next to the colored square. I'm sure it's because I've done my method wrong. This is how I get the titles:
func legendTitleForBarPlot(barPlot: CPTBarPlot, recordIndex idx: UInt) -> String? {
guard let ident = barPlot.identifier as? String else { return nil }
guard alreadyPrintedLegend[ident] == nil else { return nil }
alreadyPrintedLegend[ident] = true
return ident
}
When my plots are created I set the identifier to the name of the plot that I want displayed. If I put some print statements above I do see each plot name being printed once.

Do not implement the delegate method and the legend will show properly.
I put this as an answer so when people are searching they see this was resolved.

Related

stackView.removeArrangedSubview isn't working perfecly

I have a register View controller. I have text field for the phone number, and another text field for the country number.
i need the country code text field to be on the left and behind it, we should have the phone number.
this is working when the app is on English lang, but when the user changes the language to Arabic, we will get the phone number text field on the left not the country code on the left.
so, i tried to re-arrange the stack view. and it worked, but the size of the stack just changed!
let language = getObjectFromUserDefault(forKey: userDefaultKeys.getLanguageKey) as? String
if KLanguageCode.Arabic.rawValue == language
{
self.mobiStack.removeArrangedSubview(self.mobiStack.arrangedSubviews.first!)
self.mobiStack.removeArrangedSubview(self.mobiStack.arrangedSubviews.first!)
self.mobiStack.setNeedsLayout()
self.mobiStack.layoutIfNeeded()
self.view.layoutIfNeeded()
self.mobiStack.insertSubview(self.txtMobile, at: 0)
self.mobiStack.insertSubview(self.countryCode, at: 1)
self.mobiStack.setNeedsLayout()
self.view.layoutIfNeeded()
}
You can simplify your code like this:
// properly unwrap optional
guard let v = self.mobiStack.arrangedSubviews.last else {
return
}
self.mobiStack.insertArrangedSubview(v, at: 0)
Notes:
when adding arranged subviews, you do NOT need to remove them first.
the above code will swap the two views.
You may want to explicitly set the order (instead of just swapping them)... So, you might use a function like this:
func orderFields(_ rtl: Bool) -> Void {
if rtl {
self.mobiStack.addArrangedSubview(self.txtMobile)
self.mobiStack.addArrangedSubview(self.countryCode)
} else {
self.mobiStack.addArrangedSubview(self.countryCode)
self.mobiStack.addArrangedSubview(self.txtMobile)
}
}
You can call that when you setup your views --
The fields will be ordered as instructed... adding them if they are not already arranged subviews, or re-ordering them if they are.
Also, unless you have something else going on that you have not shown us, there is no need to be calling:
self.mobiStack.setNeedsLayout()
self.view.layoutIfNeeded()

dequeueReusableCell causes text to change color

I've got a collection view and I'm using a custom class for the cells. Each cell has two text view, chapterTitleTextView and chapterBodyTextView. I've added placeholders to both text views like so:
class CustomWriterPageCell: UICollectionViewCell, UITextViewDelegate {
// When the user taps on a text view
func textViewDidBeginEditing(_ textView: UITextView) {
if textView.textColor == .gray {
textView.text = nil
textView.textColor = .black
}
}
// When the user taps out of a text view or taps on the done button in the toolbar
func textViewDidEndEditing(_ textView: UITextView) {
// If the chapter title text view is empty
if chapterTitleTextView.text.isEmpty {
chapterTitleTextView.text = "Chapter Title"
chapterTitleTextView.textColor = .gray
}
// If the chapter body text view is empty
if chapterBodyTextView.text.isEmpty {
chapterBodyTextView.text = "Chapter Body"
chapterBodyTextView.textColor = .gray
}
}
}
How this works is that, the text color is initially gray and there is some text, when the user taps on the text view, the color changes to black and the text in the text view is removed.
Now there is this problem with using dequeueReusableCell, it’s that it reuses the cells, this caused problem number 1: Whatever I type on the text view in the first cell appears on the 4th cell, to solve this problem I had to create 2 global lists to hold whatever I type and this gets displayed in the text views of the cells, here’s the code:
Global Lists:
var chapterTitleText = Array(repeating: "", count: 4) // To store the chapter title text
var chapterBodyText = Array(repeating: "", count: 4) // To store the chapter body text
The following code snippet is inside the textViewDidEndEditing from earlier
// Append the chapter body text to the chapterBodyText array
let titleText = chapterTitleTextView.text
let titleRow = textView.tag //This the indexPath.row
chapterTitleText[titleRow] = titleText!
// Append the chapter title text to the chapterTitleText array
let bodyText = chapterBodyTextView.text
let bodyRow = textView.tag
chapterBodyText[bodyRow] = bodyText!
And in cellForItemAt:
cell.chapterBodyTextView.tag = indexPath.row
cell.chapterTitleTextView.tag = indexPath.row
cell.chapterTitleTextView.text = chapterTitleText[indexPath.row]
cell.chapterBodyTextView.text = chapterBodyText[indexPath.row]
This got rid of problem number 1 (text in the text views duplicating). But then I got a new problem, remember the placeholder text I was talking about? When I type something in the one of the textviews of the first cell, the text color of the text view in the fourth cell changes.
Here is a GIF replicating the problem:
Following your chain of questions, I suggest you to do this every time you're dealing with UICollectionView or UITableView.
Define a method in your cell class and take whatever data it needs to display itself as arguments:
func configure(text : String?) { //text is optional here which means it can be nil.
//However, from my previous answer you can replace it with an empty string condition.
if let txt = text { //or if text != ""
self.chapterTitleTextView.text = txt
self.chapterTitleTextView.text.textColor = .black
}
else {// As others mentioned make sure to always handle else because cells are reusable.
self.chapterTitleTextView.text = "Chapter Title"
self.chapterTitleTextView.text.textColor = .gray
}
}
The intuition behind reusable cells are that since they are reusable, you should reconfigure them completely and not to expect that the configuration is saved or attached to the cell.
Now, in the cellForItemAt:
let cell = ...
cell.configure(text : chapterTitleText[indexPath.row])
And remember, in this way, you do not need to define a global array. As I've told you previously, this array need to be only defined in your Controller and your cell does not need to know about it. Your cell only needs to know about one index of that array which is passed through configure function.
Although that global array will work, I'm talking about propriety in coding.
Comment your problems with this approach(if any), I will try to answer with patience but don't expect a (copy-paste)able code.
This happens because of the reuse mechanism of the UICollectionView and UITableView. Since you only update the color in one way, collection "remembers" previous color and upon new cell recreates its previous state. You have two basic solutions here.
First is to update cell state for both cases like:
if myCondition == true {
color = UIColor.gray
} else {
color = UIColor.black
}
Second is to utilize prepareForReuse method of the UICollectionViewCell
func prepareForReuse() {
// code that resets state of your cell to default
}
Method description in Apple Documentation

How to print all the staticTexts in XCUITest

I have used app.staticTexts["String"].tap() to tap on a button containing that string which is working completely fine.
But the problem here is that i want to print all the static texts which are present on that page, how can i do it in XCUITest ?
My aim here is to iterate through all the static texts present on the page and then add an if condition on my expected text.
You can use something like that:
for staticText in app.staticTexts.allElementsBoundByIndex {
if staticText.label == "test" {
}
}
//Returns all the labels,buttons, textfield,images in the page with its name.
//Just change the element name in loop according to the need.
for staticText in app.staticTexts.allElementsBoundByIndex{
if staticText != nil{
print(staticText.label)
}else{
print("No static text found")
}
}
I suppose the text is present in the identifier attribute of the staticText element. You can try the following
for i in 0..<app.staticTexts.count {
let text = app.staticTexts.element(boundBy: i).identifier
print(text)
if text == "Your String" {
// Your code
}
}

Is there any way to grab the text and detail text labels of multiple selected table view cells in swift?

I have some code right now that gets what cells were selected. The following is my code for doing that:
if let selectedUserRows = self.tableView.indexPathsForSelectedRows {
self.groupUserArray.append(selectedUserRows)
for index in selectedUserRows {
let text = groupUserArray[index.row]
print(text)
}
}
The new error is saying that the index is out of range!
I was trying to use the logic for grabbing one selected cells text but it does not work. So I was wondering if anyone knew how to grab multiple selected cell's text?
Any help would be appreciated!
self.tableView.indexPathsForSelectedRows returns a [IndexPath]? so if you obtain an array of all the rows and sections of you selected rows. I suppose you are using some sort of collection to populate your tableView (in my example I will call it textArray: [String] ) so you can do something like that to get all the text you need:
if let selectedUserIndexes = self.tableView.indexPathsForSelectedRows {
for index in selectedUserIndexes {
let text = textArray[index.row]
}
}

How to set accessibility only to annotations in map view?

I am trying to make my mapview accessible, but I have an isuue in doing so:
If I try to make the mapView accessible,by doing this:
self.mapView.isAccessibilityElement=YES;
Then, the map view is not read by the voice over.
If I set like this:
self.mapView.isAccessibilityElement=NO;
Then the voice over is reading everything in the map, streets, buildings, my current location and my annotations.
I have given the accessibility label and hints to my annotations,but I havent provided any other value to the mapview.
I also tried by setting the accessibility elements for map view:
[self.mapView setAccessibilityElements:#[self.mapView.annotations,self.mapView.userLocation]];
But still no luck.
Is there anyway to make voice over read only the annotations and neglect remaining elements like streets,buildings?
I think you're having difficulty because an MKMapView is a UIAccessibilityContainer, and so isAccessibilityElement if false by default.
You should look into making custom voice over rotors that allow the user to navigate your app by only your annotations.
This is a good approach, because it gives the user a custom, app specific way to navigate your map, while also not taking anything away from MKMapView's built in accessibility.
There are hardly any examples online that go into detail about creating custom rotors, but I just successfully created one doing exactly what you need it to do. I followed the WWDC Session 202 (begins at 24:17).
Here's my code:
func configureCustomRotors() {
let favoritesRotor = UIAccessibilityCustomRotor(name: "Bridges") { predicate in
let forward = (predicate.searchDirection == .next)
// which element is currently highlighted
let currentAnnotationView = predicate.currentItem.targetElement as? MKPinAnnotationView
let currentAnnotation = (currentAnnotationView?.annotation as? BridgeAnnotation)
// easy reference to all possible annotations
let allAnnotations = self.mapView.annotations.filter { $0 is BridgeAnnotation }
// we'll start our index either 1 less or 1 more, so we enter at either 0 or last element
var currentIndex = forward ? -1 : allAnnotations.count
// set our index to currentAnnotation's index if we can find it in allAnnotations
if let currentAnnotation = currentAnnotation {
if let index = allAnnotations.index(where: { (annotation) -> Bool in
return (annotation.coordinate.latitude == currentAnnotation.coordinate.latitude) &&
(annotation.coordinate.longitude == currentAnnotation.coordinate.longitude)
}) {
currentIndex = index
}
}
// now that we have our currentIndex, here's a helper to give us the next element
// the user is requesting
let nextIndex = {(index:Int) -> Int in forward ? index + 1 : index - 1}
currentIndex = nextIndex(currentIndex)
while currentIndex >= 0 && currentIndex < allAnnotations.count {
let requestedAnnotation = allAnnotations[currentIndex]
// i can't stress how important it is to have animated set to false. save yourself the 10 hours i burnt, and just go with it. if you set it to true, the map starts moving to the annotation, but there's no guarantee the annotation has an associated view yet, because it could still be animating. in which case the line below this one will be nil, and you'll have a whole bunch of annotations that can't be navigated to
self.mapView.setCenter(requestedAnnotation.coordinate, animated: false)
if let annotationView = self.mapView.view(for: requestedAnnotation) {
return UIAccessibilityCustomRotorItemResult(targetElement: annotationView, targetRange: nil)
}
currentIndex = nextIndex(currentIndex)
}
return nil
}
self.accessibilityCustomRotors = [favoritesRotor]
}

Resources