Allow Action When Tapping UITextView - swift

I would like to be able to effectively use a UITextView as a button in my Swift iOS application. When I tap on the text view, I don't want it to be editable, but I want it to change the background color of the text view and begin using the speech recognition software in the app. I've seen some other questions similar to this, but none answering this specific question.
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
guard textView == inView else {
guard textView == resultView else {
return false
}
nextButton.isEnabled = true
return false
}
if audioEngine.isRunning {
let myColor: UIColor = UIColor(red: 50, green: 0, blue: 0, alpha: 0.75)
inView.layer.backgroundColor = myColor.cgColor
audioEngine.inputNode.removeTap(onBus: 0)
globalVariables.boolRecording = false
audioEngine.stop()
recognitionRequest?.endAudio()
microphoneButton.isEnabled = true
microphoneButton.setTitle("Start Recording", for: .normal)
globalVariables.finalText = globalVariables.finalText + globalVariables.tempText
globalVariables.tempText = ""
self.inView.text = ""
return false
} else {
let myColor: UIColor = UIColor(red: 0, green: 50, blue: 0, alpha: 0.75)
inView.layer.backgroundColor = myColor.cgColor
globalVariables.boolRecording = true
startRecording()
microphoneButton.setTitle("Stop Recording", for: .normal)
return false
}
}

You can use UITextViewDelegate method:textViewShouldBeginEditing.
Return false from this method to prevent making this particular textfield firstResponder and change the background and start your speech recognition.
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
guard textView == speechTextView else {
return true
}
// Change bg
speechTextView.backgroundColor = UIColor.blue
// Start speech
startSpeechRecognition()
return false
}
Don't forget to add delegate of UITextview to self:
speechTextView.delegate = self

Related

How to use "shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer"

I am trying to programmatically create 6 CGRect objects on the right side of the screen, with three being blue and three red. The user would then drag them to the left side of the screen, and they need to drag the blue blocks where the target is the faded-out region of the same color. The picture below depicts what I am trying to do.
The issue is that when I drag any block over any of the faded areas, it accepts the block and deletes it. I realize that I need to implement shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer but I am confused on how to do so. I get that gestureRecognizer and otherGestureRecognizer represent the two conflicting objects, but I don't know how to implement it with the rest of my code so that I can make sure that only blue blocks can go over the faded blue block and activate the delete feature. What I have is below.
import UIKit
class ViewController: UIViewController {
private struct Constants {
static let padding: CGFloat = 75
static let correctPadding: CGFloat = 0
static let blockDimension: CGFloat = 50
}
var targetView0: UIView?
var targetView1: UIView?
var targetView2: UIView?
var targetView3: UIView?
var targetView4: UIView?
var targetView5: UIView?
var beginningPosition: CGPoint = .zero
var initialMovableViewPosition: CGPoint = .zero
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
addMovableViews(count: 6)
addtargetView0()
addtargetView1()
addtargetView2()
addtargetView3()
addtargetView4()
addtargetView5()
}
//This programtically creates the blocks w/ x and y
private func addMovableViews(count: Int) {
var xOffset = Constants.padding
for i in 0..<count {
print(i)
let movableView = UIView(frame: CGRect(x: 700, y: xOffset + 120, width: Constants.blockDimension, height: Constants.blockDimension))
if (i == 0) {
movableView.backgroundColor = .blue
view.addSubview(movableView)
let item0 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item0)
} else if (i == 1) {
movableView.backgroundColor = .red
view.addSubview(movableView)
let item1 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item1)
} else if (i == 2) {
movableView.backgroundColor = .blue
view.addSubview(movableView)
let item2 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item2)
} else if (i == 3) {
movableView.backgroundColor = .red
view.addSubview(movableView)
let item3 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item3)
} else if (i == 4) {
movableView.backgroundColor = .blue
view.addSubview(movableView)
let item4 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item4)
} else if (i == 5) {
movableView.backgroundColor = .red
view.addSubview(movableView)
let item5 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item5)
} else if (i == 6) {
movableView.backgroundColor = .blue
view.addSubview(movableView)
let item6 = UIPanGestureRecognizer(target: self, action: #selector(touched))
movableView.addGestureRecognizer(item6)
}
xOffset += Constants.blockDimension + Constants.padding
}
}
private func addtargetView0() {
let xOffset = Constants.correctPadding
targetView0 = UIView(frame: CGRect(x: xOffset + 100, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView0?.backgroundColor = UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)
view.addSubview(targetView0!)
}
private func addtargetView1() {
let xOffset = Constants.correctPadding
targetView1 = UIView(frame: CGRect(x: 100 + xOffset + 50, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView1?.backgroundColor = UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)
view.addSubview(targetView1!)
}
private func addtargetView2() {
let xOffset = Constants.correctPadding
targetView2 = UIView(frame: CGRect(x: 100 + xOffset + 100, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView2?.backgroundColor = UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)
view.addSubview(targetView2!)
}
private func addtargetView3() {
let xOffset = Constants.correctPadding
targetView3 = UIView(frame: CGRect(x: 100 + xOffset + 150, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView3?.backgroundColor = UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)
view.addSubview(targetView3!)
}
private func addtargetView4() {
let xOffset = Constants.correctPadding
targetView4 = UIView(frame: CGRect(x: 100 + xOffset + 200, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView4?.backgroundColor = UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)
view.addSubview(targetView4!)
}
private func addtargetView5() {
let xOffset = Constants.correctPadding
targetView5 = UIView(frame: CGRect(x: 100 + xOffset + 250, y: 500, width: Constants.blockDimension, height: Constants.blockDimension))
targetView5?.backgroundColor = UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)
view.addSubview(targetView5!)
}
//Gesture recognizer
#objc private func touched(_ gestureRecognizer: UIGestureRecognizer) {
if let touchedView = gestureRecognizer.view {
if gestureRecognizer.state == .began {
beginningPosition = gestureRecognizer.location(in: touchedView)
initialMovableViewPosition = touchedView.frame.origin
} else if gestureRecognizer.state == .ended {
//Moves it back to where it was
// touchedView.frame.origin = initialMovableViewPosition
} else if gestureRecognizer.state == .changed {
let locationInView = gestureRecognizer.location(in: touchedView)
touchedView.frame.origin = CGPoint(x: touchedView.frame.origin.x + locationInView.x - beginningPosition.x, y: touchedView.frame.origin.y + locationInView.y - beginningPosition.y)
if touchedView.frame.intersects(targetView0!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView0?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if touchedView.frame.intersects(targetView1!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView1?.backgroundColor = .red
initialMovableViewPosition = .zero
}
if touchedView.frame.intersects(targetView2!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView2?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if touchedView.frame.intersects(targetView3!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView3?.backgroundColor = .red
initialMovableViewPosition = .zero
}
if touchedView.frame.intersects(targetView4!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView4?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if touchedView.frame.intersects(targetView5!.frame) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView5?.backgroundColor = .red
initialMovableViewPosition = .zero
}
}
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer)
-> Bool {
// If the gesture recognizers are on diferent views, do not allow
// simultaneous recognition.
if gestureRecognizer.view != otherGestureRecognizer.view {
return false
}
return true
}
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Can someone explain how to incorporate shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer, link a complete project doing something similar, or walk me through it. Any help is appreciated.
There are a few issues here. Firstly, the delegate for your gestures are not being set. To do this, you need ViewController to extend UIGestureRecognizerDelegate like so class ViewController: UIViewController, UIGestureRecognizerDelegate. Then, you need to set the delegate of each of your gestures to your ViewController:
let item0 = UIPanGestureRecognizer(target: self, action: #selector(touched))
item0.delegate = self
movableView.addGestureRecognizer(item0)
Second, even with the delegates set, shouldRecognizeSimultaneouslyWith would never be called since you only have one type of gesture (UIPanGestureRecognizer) for each of your moveable views. Your target views themselves do not have any gesture recognisers assigned to them. If you want to test when shouldRecognizeSimultaneouslyWith is called, you can try do the following:
let item0 = UIPanGestureRecognizer(target: self, action: #selector(touched))
item0.delegate = self
movableView.addGestureRecognizer(item0)
// Add another gesture
let testitem = UITapGestureRecognizer(target: self, action: #selector(test))
movableView.addGestureRecognizer(testitem)
With the example above, both UITapGestureRecognizer and UIPanGestureRecognizer would be triggered the moment you start dragging the moveable views.
=== Solution ===
Instead of using shouldRecognizeSimultaneouslyWith might I suggest adding tags to each of your moveable and target views? For example, for all blue moveable and target views, movableView.tag = 0 and for all red moveable and target views, movableView.tag = 1.
Then, in your touched action, you can just check if the tags match like so:
if touchedView.frame.intersects(targetView0!.frame) {
if touchedView.tag == targetView0?.tag {
touchedView.removeFromSuperview()
targetView0?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
}
I figured it out. It's basically just in the gesture if statement.
#objc private func touched(_ gestureRecognizer: UIGestureRecognizer) {
if let touchedView = gestureRecognizer.view {
if gestureRecognizer.state == .began {
beginningPosition = gestureRecognizer.location(in: touchedView)
initialMovableViewPosition = touchedView.frame.origin
} else if gestureRecognizer.state == .ended {
//Moves it back to where it was
// touchedView.frame.origin = initialMovableViewPosition
} else if gestureRecognizer.state == .changed {
let locationInView = gestureRecognizer.location(in: touchedView)
touchedView.frame.origin = CGPoint(x: touchedView.frame.origin.x + locationInView.x - beginningPosition.x, y: touchedView.frame.origin.y + locationInView.y - beginningPosition.y)
if ((touchedView.backgroundColor == .blue) && (targetView0?.backgroundColor == UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView0!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView0?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if ((touchedView.backgroundColor == .red) && (targetView1?.backgroundColor == UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView1!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView1?.backgroundColor = .red
initialMovableViewPosition = .zero
}
if ((touchedView.backgroundColor == .blue) && (targetView2?.backgroundColor == UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView2!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView2?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if ((touchedView.backgroundColor == .red) && (targetView3?.backgroundColor == UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView3!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView3?.backgroundColor = .red
initialMovableViewPosition = .zero
}
if ((touchedView.backgroundColor == .blue) && (targetView4?.backgroundColor == UIColor(red: 51/255.0, green: 153/255.0, blue: 255/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView4!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView4?.backgroundColor = .blue
initialMovableViewPosition = .zero
}
if ((touchedView.backgroundColor == .red) && (targetView5?.backgroundColor == UIColor(red: 255/255.0, green: 102/255.0, blue: 102/255.0, alpha: 1)) && (touchedView.frame.intersects(targetView5!.frame))) {
touchedView.removeFromSuperview() //Might uncomment when everything is set up so it deals with the overlay issue
// gestureRecognizer.isEnabled = false
targetView5?.backgroundColor = .red
initialMovableViewPosition = .zero
}
}
}
}
You check if the gestureRecognizer background color is blue, check if the targetView background color is the faded blue via UIColor, and see if the view intersects, and then you do what you need. You can even do it to fill the target view in the order you want with an additional if statement.

Table View Lag (even after removing gesture recognizers)

Currently, I have a table view that lags when there are multiple cells. When there is only one cell, it performs smoothly; however, when multiple cells are populated, the table view has a slow feeling, sometimes stutters, and is not as smooth. I removed the gesture recognizers and instead changed it to didSelectRowAt, however there is still lag within the cells. Here is the code for the when the cells are loaded :
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if queryComplete == true {
if displayConvo == true {
let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell", for: indexPath as IndexPath) as! messageTableViewCell
cell.profileImage.image = nil
cell.selectionStyle = UITableViewCell.SelectionStyle.none
var convoContent: messagesViewController.Convo
convoContent = convoList[indexPath.row]
convoContent.itemHeroID = "\(String(describing: convoContent.convoID))"
cell.name.heroID = "\(String(describing: convoContent.convoID))"
cell.lastMessage.text = convoContent.lastMessage
cell.backgroundColor = UIColor.clear
cell.postText.text = convoContent.postContent
if convoContent.revealedBool == true {
cell.profileImage.isHidden = false
cell.profileImage.heroID = "\(String(describing: convoContent.convoID))"
cell.name.text = convoContent.name
cell.timer.isHidden = true
if convoContent.profileImage == "nil" || convoContent.profileImage == nil {
let url = URL(string:"https://firebasestorage.googleapis.comasdjfjaisfdji")
let processor = RoundCornerImageProcessor(cornerRadius: cell.profileImage.frame.size.width / 2)
cell.profileImage.kf.setImage(with: url, placeholder: nil, options: [.processor(processor)])
}
else {
let url = URL(string: convoContent.profileImage!)
let processor = RoundCornerImageProcessor(cornerRadius: cell.profileImage.frame.size.width / 2)
cell.profileImage.kf.setImage(with: url, placeholder: nil, options: [.processor(processor)])
}
}
else {
cell.profileImage.isHidden = true
cell.timer.isHidden = false
cell.timer.isUserInteractionEnabled = false
cell.timer.heroID = "\(String(describing: convoContent.convoID))"
let postDuration = convoContent.timeOfDeletion! - Int(convoContent.time!)
let currentTime = Date().timeIntervalSince1970 * 1000
let difference = Int(round(Double(convoContent.timeOfDeletion! - Int(currentTime))))
let date = Date(timeIntervalSinceNow: TimeInterval(difference / 1000))
cell.name.text = String(timeToDelete(date: date as NSDate, numericDates: false))
let amountOfCircleCovered = (Double(((convoContent.timeOfDeletion!) - Int(currentTime))) / Double(postDuration)) * 100
var timerColor: UIColor?
switch amountOfCircleCovered {
case 0..<30:
timerColor = UIColor (red: 252/255, green: 110/255, blue: 81/255, alpha: 1)
case 30..<60:
timerColor = UIColor (red: 255/255, green: 215/255, blue: 0/255, alpha: 1)
case 60..<100:
timerColor = UIColor(red: 26/255, green: 152/255, blue: 252/255, alpha: 1.0)
default:
timerColor = UIColor(red: 26/255, green: 152/255, blue: 252/255, alpha: 1.0)
}
print(amountOfCircleCovered)
cell.timer.models = [ PieSliceModel(value: Double(100 - amountOfCircleCovered), color: UIColor(red: 220/255, green: 220/255, blue: 220/255, alpha: 1)),
PieSliceModel(value: Double(amountOfCircleCovered), color: timerColor!),
]
}
let lastMessageDate = Date(timeIntervalSince1970: TimeInterval(convoContent.timeOfLastMessage! / 1000))
cell.timeOfLastMessage.text = String(timeAgo(date: lastMessageDate as NSDate, numericDates: false))
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell", for: indexPath as IndexPath) as! messageTableViewCell
cell.lastMessage.text = "No new messages"
return cell
}
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell", for: indexPath as IndexPath) as! messageTableViewCell
print ("loading")
return cell
}
}
Additionally, I have tried moving some of the aspects of the cell so they can be reset each time by putting them in the cell file:
override func awakeFromNib() {
super.awakeFromNib()
profileImage.cornerRadius = profileImage.frame.size.width / 2
profileImage.clipsToBounds = true
profileImage.layer.borderColor = UIColor.white.cgColor
profileImage.layer.borderWidth = 1
timer.innerRadius = 0
timer.outerRadius = timer.frame.width / 2
timer.animDuration = 0.0
timer.referenceAngle = 270
timer.backgroundColor = UIColor.white
postText.layer.zPosition = 1
if !UIAccessibility.isReduceTransparencyEnabled {
glossyView.backgroundColor = .clear
let blurEffect = UIBlurEffect(style: .regular)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
//always fill the view
blurEffectView.frame = self.glossyView.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
glossyView.addSubview(blurEffectView) //if you have more UIViews, use an insertSubview API to place it where needed
} else {
glossyView.backgroundColor = .black
}
timer.selectedOffset = 0
glossyView.clipsToBounds = true
glossyView.cornerRadius = 12.0
glossyView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
messageBackground.clipsToBounds = true
messageBackground.cornerRadius = 12.0
messageBackground.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
// glossyView.roundCornersView(corners: [.topLeft, .topRight], radius: 12.0)
// messageBackground.roundCornersView(corners: [.bottomLeft,.bottomRight], radius: 12.0)
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
profileImage.image = nil
timer.isHidden = true
timer.models = []
}
}
And yet, when multiple cells are loaded, the table view still lags. I made sure there are no gesture recognizers as this link suggests and also the images are being loaded using a library so I am not sure why the cells still lag.
Essentially, the UI was dramatically slowing down the performance. I switched out the pie time CA Layer for png images of circles partially filled, and removed all Hero animations. As a result, both the app and tableview became much smoother.

How to enable a button in different cases in swift?

I want to disable, and enable a button in different cases:
If the user comes to my share viewController the button will be disabled:
func handleShareAndAbortButton() {
shareButton.isEnabled = false
abortButton.isEnabled = false
let attributedShareButtonText = NSAttributedString(string: shareButton.currentTitle!, attributes: [NSAttributedString.Key.foregroundColor: UIColor(red: 0, green: 0, blue: 0, alpha: 0.2) ])
let attributedabortButtonText = NSAttributedString(string: abortButton.currentTitle!, attributes: [NSAttributedString.Key.foregroundColor: UIColor(red: 0, green: 0, blue: 0, alpha: 0.2) ])
shareButton.setAttributedTitle(attributedShareButtonText, for: .normal)
abortButton.setAttributedTitle(attributedabortButtonText, for: .normal)
}
The handleShareAndAbortButton will be called in viewDidLoad
If something changed (picture or text) I want to enable the button:
func imageDidChange() {
selectedText = postTextView.text!
let isText = selectedText
let isImage = selectedImage != nil
if isImage || isText != "Schreibe etwas..." && isText != nil {
shareButton.isEnabled = true
abortButton.isEnabled = true
let attributedShareButtonText = NSAttributedString(string: shareButton.currentTitle!, attributes: [NSAttributedString.Key.foregroundColor: UIColor(red: 255, green: 255, blue: 255, alpha: 1.0) ])
let attributedabortButtonText = NSAttributedString(string: abortButton.currentTitle!, attributes: [NSAttributedString.Key.foregroundColor: UIColor(red: 0, green: 0, blue: 0, alpha: 1.0) ])
shareButton.setAttributedTitle(attributedShareButtonText, for: .normal)
abortButton.setAttributedTitle(attributedabortButtonText, for: .normal)
}
}
I call the imageDidChange in viewWillAppear
Here I delete the placeholder after begin editing:
extension ShareViewController: UITextViewDelegate {
func textViewDidBeginEditing(_ textView: UITextView) {
if postTextView.textColor == UIColor.lightGray {
postTextView.text = nil
postTextView.textColor = UIColor.black
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if postTextView.text.isEmpty {
postTextView.text = "Schreibe etwas..."
postTextView.textColor = UIColor.lightGray
}
}
}
When the user now enter some text, the placeholder "Schreibe etwas..." will be gone and the text will be also != nil. But its not working.
Update
I found out the problem. When I delete the isText != "Schreibe etwas..."
it works. But I need this. How can I compare to a String? If I don't have this code, the user is able to upload always with placeholder text.
Thanks in advance for your help!
You never call imageDidChange after you changed the text.
Use:
func textViewDidEndEditing(_ textView: UITextView) {
if postTextView.text.isEmpty {
postTextView.text = "Schreibe etwas..."
postTextView.textColor = UIColor.lightGray
}
imageDidChange()
}
I see that you’re using UITextField. You probably want to have just placeholder "Schreibe etwas...". So, in viewDidLoad or in Storyboard set placeholder of your TextField to "Schreibe etwas...". Then you don’t need TextField’s delegate methods for setting text and color of text in delegate methods.
Well, you need it, but not for this. You have to call imageDidChange in textFieldDidEndEditing
Now change declaring isText. You just passed reference for selectedText. Don’t do this, just check if there is text
let isText = !selectedText.isEmpty // don’t forget to !
also rewrite your conditions
if isImage || isText
... you don’t need to check if isText isn’tnil

How to customise UISearchController?

I'm using a UISearchController in my application but I can't figure a way to customise it. I looked here in Stackoverflow but none of the confirmed answers worked for me. I tried looking in more places but nothing works.
This is my code:
import UIKit
class MainVC: UIViewController {
lazy var mSearchBarController: UISearchController = {
let mSearchBar = UISearchController(searchResultsController: nil)
mSearchBar.searchBar.barStyle = .default
mSearchBar.searchBar.placeholder = "enter city here"
mSearchBar.searchBar.tintColor = UIColor.white
return mSearchBar
}()
override func viewDidLayoutSubviews() {
setupSearchBar()
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red: 80/255, green: 135/255, blue: 179/255, alpha: 1.0)
setupNavBar()
self.navigationItem.searchController = mSearchBarController
}
private func setupNavBar(){
navigationItem.title = "Home"
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.hidesSearchBarWhenScrolling = true
}
private func setupSearchBar(){
let mSearchTextField = mSearchBarController.searchBar.value(forKey: "searchField") as? UITextField
mSearchTextField?.textColor = UIColor(red: 255/255, green: 245/255, blue: 139/255, alpha: 1.0)
let mAttributedPlaceholder = NSMutableAttributedString(string: "enter city here", attributes: [NSAttributedString.Key.foregroundColor : UIColor(red: 255/255, green: 245/255, blue: 139/255, alpha: 1.0)])
mSearchTextField?.attributedPlaceholder = mAttributedPlaceholder
for view in mSearchBarController.searchBar.subviews {
for subview in view.subviews {
if let textField = subview as? UITextField {
textField.backgroundColor = UIColor.red
textField.textColor = UIColor.white
}
}
}
}
}
I can't figure a way to change the textColor of the searchBar nor the backgroundColor of it.
This is what I get:
See I use this simple code to change the textColor and backgroundColor of seacrhBar:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
for view in searchBar.subviews {
for subview in view.subviews {
if let textField = subview as? UITextField {
textField.backgroundColor = UIColor.red
textField.textColor = UIColor.white
}
}
}
}
for reference you can check:-
How can I change the UISearchBar search text color? (for textcolor)
http://jitu1990.blogspot.com/2017/06/textcolor-and-backgroundcolor.html (for backgorund color)

How to add Animation Button like this?

How can I create an animated and shadowed button like in this video
(Once you click the button, it shines and swings)
Here is my code:
(This code implement swing and shadow but needs to be organized and arranged so that it is capable of running the light and the swing with one click and the button doesn't move from its place unnecessarily)
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var aBtn: ButtonWithShadow!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func btnClick(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
sender.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.50).cgColor
sender.layer.shadowOffset = CGSize(width: 0, height: 3)
sender.layer.shadowOpacity = 1.0
sender.layer.shadowRadius = 10.0
sender.layer.masksToBounds = false
} else {
sender.isSelected = true
sender.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.0).cgColor
}
aBtn.layer.anchorPoint = CGPoint(x: 0.5, y: 0)
aBtn.layer.transform = CATransform3DMakeRotation(-.pi / 15, 0, 0, 1)
let needleAnim = CABasicAnimation(keyPath: "transform.rotation.z")
needleAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
needleAnim.duration = 1.0 as? CFTimeInterval ?? CFTimeInterval()
needleAnim.repeatCount = 5
needleAnim.autoreverses = true
// Setting fillMode means that, once the animation finishes, the needle stays in its end position.
needleAnim.fillMode = kCAFillModeForwards
needleAnim.isRemovedOnCompletion = true
needleAnim.toValue = Double.pi / 15
aBtn.layer.add(needleAnim, forKey: nil)
}
}
and
import UIKit
class ButtonWithShadow: UIButton {
override func draw(_ rect: CGRect) {
//updateLayerProperties()
}
}
Thanks for your time
Your code works as written and provides a swinging button when clicked. Make sure you control-click dragged from the button to the button definition.
You'll need to add two images to your button, one for the off state and one for the on state.
and on
Here is the intermediate result of adding setting the images.
and the way to change the images is to add them to the assets catalog and then change them with :
if sender.isSelected {
sender.isSelected = false
sender.setImage(#imageLiteral(resourceName: "off"), for: .normal)
sender.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.50).cgColor
sender.layer.shadowOffset = CGSize(width: 0, height: 3)
sender.layer.shadowOpacity = 1.0
sender.layer.shadowRadius = 10.0
sender.layer.masksToBounds = false
} else {
sender.isSelected = true
sender.setImage(#imageLiteral(resourceName: "onbtn"), for: .normal)
sender.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.0).cgColor
}