So I have an issue where I've made a subclass of UITextView to change the various colors before and after focusing. I've found thought that after actually entering in text it pretty much disregards the text color I specified.
My code looks like below. Note, I have a dictionary called colors that maps state ("focused" or "unfocused") to another dictionary containing the colors for the field's background and text
func setColors(state:String) {
self.attributedPlaceholder = NSAttributedString(string: (self.attributedPlaceholder?.string)!, attributes: [NSForegroundColorAttributeName: self.colors[state]!["text"]!])
self.backgroundColor = self.colors[state]!["background"]
self.layer.borderColor = self.colors[state]!["background"]!.CGColor
self.textColor = self.colors[state]!["text"]
self.tintColor = self.colors[state]!["text"]
}
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator)
if context.nextFocusedView == self {
coordinator.addCoordinatedAnimations({ () -> Void in
self.setColors("focused")
}, completion: nil)
}
else {
coordinator.addCoordinatedAnimations({ () -> Void in
self.setColors("unfocused")
}, completion: nil)
}
}
So before I type in anything it looks fine. Switching between fields on the view the colors all look right. However when I select a field and enter in text afterwards the only thing that looks right is the background color, which changes as appropriate when focused/unfocused. Is there another text color attribute that is set after text is entered in?
Related
In a couple of my apps, I have an image covering the view in the background. In my asset catalog, my image has an Any, light and dark variation. In iOS 13, when I launch the app, the correct light or dark mode image is displayed according to the mode set. However, when I switch the mode while the app is running, the image does not change. All other properties change (colors etc) for all controls, but not the image.
I have tried the following with a layoutIfNeeded() and/or layoutSubviews() inside the traitCollectiosnDidChange block:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard let previousTraitCollection = previousTraitCollection else {return}
if #available(iOS 13.0, *) {
if previousTraitCollection.hasDifferentColorAppearance(comparedTo: traitCollection) {
print("Changed mode")
self.view.layoutIfNeeded()
self.view.layoutSubviews()
}
}
}
and the Change mode is definitely triggered but the layout does not change.
Is there a way to make sure that the image also displays the correct one?
OK. To answer my own question. I was applying .withHorizontallyFlippedOrientation() to my image and setting it in ViewDidLoad. When I changed the trait color mode, this image was not getting change.
The solution was to to reset the image AND the flip property when the differentColorAppearance triggers. Like this
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard let previousTraitCollection = previousTraitCollection else {return}
if #available(iOS 13.0, *) {
if previousTraitCollection.hasDifferentColorAppearance(comparedTo: traitCollection) {
image2.image = UIImage(named: "CourseImage")?.withHorizontallyFlippedOrientation()
}
}
}
Please don't mark as duplicate because I seem to have a bug where the usual code doesn't work. I went through all the available threads but haven't found a solution.
I have the following cell:
When the UISwitch is turned off, I want the UITextField to be dark and text color bright. When turned on the opposite to simulate a "disable" behavior.
My code:
func setTextFieldActivation(isOn: Bool) {
self.theTextField.isUserInteractionEnabled = isOn
self.theTextField.set(
bgColor: isOn ? Colors.moreLightGrey : Colors.leastLightGray, //Colors is a global struct of UIColor to cache reused colors
placeholderTxt: String(),
placeholderColor: isOn ? Colors.black : Colors.white,
txtColor: isOn ? Colors.black : Colors.white
)
}
The extension set
extension UITextField {
func set(bgColor: UIColor, placeholderTxt: String, placeholderColor: UIColor, txtColor: UIColor) {
self.backgroundColor = bgColor
self.attributedPlaceholder = NSAttributedString(string: placeholderTxt, attributes: [NSForegroundColorAttributeName: placeholderColor])
self.textColor = txtColor
}
}
The issue: When I turn on the UISwitch, the background color changes as wanted but the text color remains.
The weird part: When I click the UITextField and it becomes first responder, the text color changes to what I want.
But when I turn the Switch off again, the color remains dark.
What am I missing? Help is very appreciated.
PS: Xcode 9, Swift 3.
The code is called whenever the switch is changed:
self.theSwitch.addTarget(self, action: #selector(switchChanged), for: .valueChanged)
func switchChanged(mySwitch: UISwitch) {
self.setTextFieldActivation(isOn: mySwitch.isOn)
}
I think I figured it out. The wired thing is that the textColor is not updated until layoutSubviews(). I tried two approaches which seem to solve the problem.
The first approach is to call layoutSubviews() directly at the end of the set method
func set(bgColor: UIColor, placeholderTxt: String, placeholderColor: UIColor, txtColor: UIColor) {
backgroundColor = bgColor
attributedPlaceholder = NSAttributedString(string: placeholderTxt, attributes: [NSForegroundColorAttributeName: placeholderColor])
textColor = txtColor
layoutSubviews()
}
The second approach is to set the text for the UITextField to it's current value which will trigger layoutSubviews() as well.
func set(bgColor: UIColor, placeholderTxt: String, placeholderColor: UIColor, txtColor: UIColor) {
backgroundColor = bgColor
attributedPlaceholder = NSAttributedString(string: placeholderTxt, attributes: [NSForegroundColorAttributeName: placeholderColor])
textColor = txtColor
let newText = text
text = newText
}
I have a UITextView and I need to detect the String which will be a colour that the user has typed in it. Then I need to change the colour of the text in the UITextField to the colour typed by the user.
For example: if I type 'red' in the textField, the colour of the text should change to red.
Does anyone know how this can be done?
Thanks!
As a starting point, you'd need to create a mapping of String to UIColor.
let colorMapping: [String: UIColor] = [
"green": .green,
"white": .white,
//etc...
]
Start by mapping the text of each color to its appropriate UIColor:
let colors: [String: UIColor] = [
// add any built-in colors
"red": .red,
"blue": .blue,
// custom colors too!
"goldenrod": UIColor(red: 218, green: 165, blue: 32)
// add all the colors you wish to detect
// ...
// ...
]
Make the view controller containing your text field conform to UITextViewDelegate and implement the shouldChangeTextIn function (gets called whenever the user enters/deletes a character):
class MyViewController: UIViewController, UITextFieldDelegate {
// ... other view controller code
func textField(_ textField: UITextField, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if let currentText = textField.text {
// check if the text is in the `colors` dictionary
// and if so, apply the color to the `textColor`
if colors.keys.contains(currentText) {
textField.textColor = colors[currentText]
}
}
return true
}
// ... other view controller code
}
You can detect the text in textfield using the below delegate method
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
//Don't forgot to make user entered content to lowercaseString while checking with colorCollection
if colorCollection.keys.contains(textField.text.lowercaseString) {
textField.textColor = colorCollection[currentText] //If entered content match with any colour then it will change the text colour of textfield
}
return true
}
Create simple collection of color like below
let colorCollection: [String: UIColor] = [
"blue": .blue,
"purple": .purple,
//your other coolers
]
So assuming you have textfield and textview outlet or created programmatically:-
let textField = UITextField()
let txtVw = UITextView()
//If enter some text inside textfield for instance red then get the value, compare it and set the text color on textview
if textField.text?.lowercased() == "red" {
txtVw.textColor = UIColor.red
}
I'm trying to print with a printer, the plain text content of a NSTextView which has a black background and a white text (no images, only unformatted text).
I'm using this code:
mainTextField.print(Any?.self)
Unfortunately the print (preview) looks like black with a white text on it, apart from that I would use an ink of cartridge for each paper, it is not good even for the environment. Is there a way to just print the text without background and text color attributes?
Just create a new NSTextView when you want to print.
#IBAction func printButtonClicked(_ sender: Any) {
let tv = NSTextView(frame: textView.frame)
tv.string = textView.string
tv.print(tv)
}
--- Update: with rich text.---
#IBAction func printButtonClicked(_ sender: Any) {
let tv = NSTextView(frame: textView.frame)
if textView.isRichText {
let data = textView.rtf(from: NSMakeRange(0, (textView.string! as NSString).length))
tv.replaceCharacters(in: NSMakeRange(0, 0), withRTF: data!)
tv.textColor = .black
}
else {
tv.string = textView.string
}
tv.print(nil)
}
In my project, I print the text content of a text view via the codes. Swift 4 on iOS 10
func printContent() {
let printer = UIPrintInteractionController.shared
printer.printFormatter = UISimpleTextPrintFormatter(attributedText: self.contentView.attributedText)
printer.present(animated: true) { printer, success, error in
print("print success: \(success)")
}
}
I have a simple imageView added to a custom UICollectionViewCell. I initialize it when i declare it:
let likeIcon = UIImageView()
And then I set properties in my class' initializer:
likeIcon.image = UIImage(named: "heart_empty")!
likeIcon.alpha = 0.0
addSubview(likeIcon)
Nothing too crazy. I want the imageView to be hidden initially but then visible when the cell is clicked.
I have a simple method that I call when the cell is selected (it's not animated yet):
func toggleLikeButtonAnimated() {
likeIcon.frame = likeIconFrame()
likeIcon.alpha = 1.0
}
But the icon doesn't show.
If I comment out the initial likeIcon.alpha = 0.0 then the icon is visible selected or unselected, so it's there
toggleLikeButtonAnimated is definitely called
The frame is the correct frame
The only thing I can think of, since this is really strange, is that something with the focus engine is interfering with the alpha changing.
I have this code in the cell right now:
// MARK: -- Focus
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator)
coordinator.addCoordinatedAnimations({ () -> Void in
if self.focused {
self.focusItem()
} else {
self.unfocusItem()
}
}) { () -> Void in
}
}
func focusItem() {
self.overlay.alpha = 0.0
}
func unfocusItem() {
self.overlay.alpha = 0.6
}
The overlay is below the icon so it shouldn't interfere with it's visibility. So I tried this:
// MARK: -- Focus
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator)
coordinator.addCoordinatedAnimations({ () -> Void in
if self.focused {
self.focusItem()
} else {
self.unfocusItem()
}
}) { () -> Void in
}
}
func focusItem() {
self.overlay.alpha = 0.0
self.likeIcon.alpha = 1.0
}
func unfocusItem() {
self.overlay.alpha = 0.6
self.likeIcon.alpha = 0.0
}
The likeIcon animates in when the cell is focused and out when unfocused. But this is not what I want, and it seems like the animation of the focus engine is preventing my alpha change when selected.
Any ideas on how to fix?
According your description,you want the imageView to be hidden initially but then visible when the UICollectionViewCell is clicked, but it is did't work. When you set UICollectionViewDelegate,you must be call reloadData function,just like UITableView.Maybe you can try use this when you click cell.Solve you problem yet.