Copy button from Label.
I have code for the calculator but I can not figure out how to do it so that when I click on the button, the number with the Label is copied.
Or how can I make it so that when I press long it appears to copy:
"
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var displayResultLabel: UILabel!
var stillTyping = false
var dotIsPlaced = false
var firstOperand: Double = 0
var secondOperand: Double = 0
var operationSign: String = ""
var currentInput: Double {
get {
return Double (displayResultLabel.text!)!
}
set {
let value = "\(newValue)"
let ValueArray = (value.components(separatedBy:"."))
if ValueArray[1] == "0" {
displayResultLabel.text = "\(ValueArray[0])"
} else {
displayResultLabel.text = "\(newValue)"
}
stillTyping = false
}
}
#IBAction func numberPressed(_ sender: UIButton) {
let number = sender.currentTitle!
if stillTyping {
if (displayResultLabel.text?.characters.count)! < 20 {
displayResultLabel.text = displayResultLabel.text! + number
}
} else {
displayResultLabel.text = number
stillTyping = true
}
}
#IBAction func twoOperandsSignPressed(sender: UIButton) {
operationSign = sender.currentTitle!
firstOperand = currentInput
stillTyping = false
dotIsPlaced = false
}
func operateWithTwoOperands(operation: (Double, Double) -> Double) {
currentInput = operation(firstOperand, secondOperand)
stillTyping = false
}
#IBAction func equalitySignPressed(sender: UIButton) {
if stillTyping {
secondOperand = currentInput
}
dotIsPlaced = false
switch operationSign {
case "+":
operateWithTwoOperands{$0 + $1}
case "-":
operateWithTwoOperands{$0 - $1}
case "×":
operateWithTwoOperands{$0 * $1}
case "÷":
operateWithTwoOperands{$0 / $1}
default: break
}
}
#IBAction func dotButtonPressed(_ sender: UIButton) {
if stillTyping && !dotIsPlaced {
displayResultLabel.text = displayResultLabel.text! + "."
dotIsPlaced = true
} else if !stillTyping && !dotIsPlaced {
displayResultLabel.text = "0."
}
}
}
I will answer both of your questions.
The first question: How to press a button that can copy the text that is being displayed on the UILabel?
Answer:
#IBAction func yourButtonAction(_ sender: UIButton) {
UIPasteboard.general.string = yourLabel.text
}
The second question: How to long-press on the UILabel that shows the "Copy" action?
Answer:
To make UILabel copyable we need to create a custom class that is a subclass of UILabel. Temporarily called CopyableLabel:
import UIKit
class CopyableLabel: UILabel {
override var canBecomeFirstResponder: Bool { return true }
override init(frame: CGRect) {
super.init(frame: frame)
sharedInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
sharedInit()
}
override func copy(_ sender: Any?) {
UIPasteboard.general.string = text
UIMenuController.shared.setMenuVisible(false, animated: true)
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return action == #selector(copy(_:))
}
}
// MARK: Actions methods
extension CopyableLabel {
func longPressGestureActionHandler(_ sender: UILongPressGestureRecognizer) {
becomeFirstResponder()
let menu = UIMenuController.shared
if !menu.isMenuVisible {
menu.setTargetRect(bounds, in: self)
menu.setMenuVisible(true, animated: true)
}
}
}
// MARK: Helper methods
extension CopyableLabel {
func sharedInit() {
isUserInteractionEnabled = true
addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(longPressGestureActionHandler(_:))))
}
}
And use a CopyableLabel instead of a pure UILabel:
let yourLabel: CopyableLabel = CopyableLabel()
If you use the Interface Builder, make sure you've defined the base class of your Label:
You can implement copy and paste with UIPasteboard. You can read and write values over it's property string, e.g.:
displayResultLabel.text = UIPasteboard.general.string
pastes the current value from the pasteboard into your label, and
UIPasteboard.general.string = displayResultLabel.text
copies the value from label to the pasteboard.
Related
I am trying to build an IOS app where the user puts options in to a tableview, then the options appear and the spinning frame spins and stops at a random point.
I have put all the necessary code in ViewWillAppear but for some reason the app doesn't update with the user defaults, only when i close the app and re-open it.
It did actually work at one point but then stopped and i have no idea how to fix it. I am using TTFortuneWheel Pod.
ImageOne
ImageTwo
I will link my GitHub in case anyone wants to have a look at the full code.
https://github.com/jamesnjones/Just.Decide
below is the code for the main screen
import UIKit
import TTFortuneWheel
import AVFoundation
class ViewController: UIViewController, UINavigationControllerDelegate {
#IBOutlet weak var spinningWheel: TTFortuneWheel!
#IBOutlet weak var ResultsLabel: UILabel!
let transition = SlideInTransition()
var slices : [CarnivalWheel] = []
var result: String?
var player: AVAudioPlayer!
var soundIsOn = true
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.delegate = self
spinningWheel.initialDrawingOffset = 270.0
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("check")
slices = getSlices()
spinningWheel.slices = slices
spinningWheel.equalSlices = true
spinningWheel.frameStroke.width = 0
spinningWheel.titleRotation = CGFloat.pi
spinningWheel.slices.enumerated().forEach { (pair) in
let slice = pair.element as! CarnivalWheel
let offset = pair.offset
switch offset % 6 {
case 0: slice.style = .blue
case 1: slice.style = .green
case 2: slice.style = .grey
case 3: slice.style = .orange
case 4: slice.style = .purple
default: slice.style = .yellow
}
}
}
private func getSlices() -> [CarnivalWheel] {
PersistenceManager.retrieveSlices { [weak self] result in
guard let self = self else {return}
switch result {
case .success(let slices):
if slices.isEmpty {
print("this is where i will add an alert or sumin")
}else {
self.slices = slices
DispatchQueue.main.async {
self.reloadInputViews()
}
}
case .failure(let error):
print("Edit VC Errror ")
}
}
return slices
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
true
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
true
}
#IBAction func rotateButton(_ sender: UIButton) {
if soundIsOn {
playSound(soundName: "spinning")
ResultsLabel.text = ""
let randomNumber = Int.random(in: 0...slices.count - 1)
spinningWheel.startAnimating()
DispatchQueue.main.asyncAfter(deadline: .now() + 0) {
self.spinningWheel.startAnimating(fininshIndex: randomNumber) { (finished) in
self.ResultsLabel.text = self.spinningWheel.slices[randomNumber].title
}
}
} else {
ResultsLabel.text = ""
let randomNumber = Int.random(in: 0...slices.count - 1)
spinningWheel.startAnimating()
DispatchQueue.main.asyncAfter(deadline: .now() + 0) {
self.spinningWheel.startAnimating(fininshIndex: randomNumber) { (finished) in
self.ResultsLabel.text = self.spinningWheel.slices[randomNumber].title
}
}
}
}
Rather than putting it inside of your viewWillAppear put it inside of the viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
<#code#>
}
Here's what my textView looks like right now. It is a textview inside a scrollview.
I am trying to replace the usual UIMenuController menu items with Save and Delete but not getting there. Can someone help me out?
Here's my code:
import UIKit
class DetailViewController: UIViewController, UIGestureRecognizerDelegate, {
var selectedStory : URL!
#IBOutlet weak var textView: UITextView!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var textSlider: UISlider! {
didSet {
configureSlider()
}
}
override func viewDidLoad() {
super.viewDidLoad()
let storyText = try? String(contentsOf: selectedStory)
textView.text = storyText
textView.isUserInteractionEnabled = true
let longPressGR = UILongPressGestureRecognizer(target: self, action: #selector(longPressHandler))
longPressGR.minimumPressDuration = 0.3 //
textView.addGestureRecognizer(longPressGR)
}
// MARK: - UIGestureRecognizer
#objc func longPressHandler(sender: UILongPressGestureRecognizer) {
guard sender.state == .began,
let senderView = sender.view,
let superView = sender.view?.superview
else { return }
senderView.becomeFirstResponder()
UIMenuController.shared.setTargetRect(senderView.frame, in: superView)
UIMenuController.shared.setMenuVisible(true, animated: true)
}
override var canBecomeFirstResponder: Bool {
return true
}
}
extension UITextView{
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == Selector(("_copy:")) || action == Selector(("_share:"))
{
return true
} else {
return false
}
}
}
extension UIScrollView{
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == Selector(("_copy:")) || action == Selector(("_share:"))
{
return true
} else {
return false
}
}
}
I'm getting 2 issues:
When I tap the screen, only the Share is showing up and the Copy is not.
The Share button shows up randomly near the center, not on the text that is selected, like so.
First of all, remove UITextView that is inside UIScrollView because UIScrollView itself is the parent class of UITextView. It will place the UIMenuController at appropriate frame.
Remove longPressGR and longPressHandler methods.
Replace this method,
extension UITextView{
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action.description == "copy:" || action.description == "_share:" {
return true
} else {
return false
}
}
}
You will get following output.
I'm trying to set a UILabel text as follows (All the following code is swift3)
// button Action which select a random text
#IBAction func getResultButton(_ sender: TransitionButton) {
if( typeTextField.text == "ABC" && pickedCompanyField.text != "XYZ"){
// query
sender.startAnimation()
// sleep(5)
sender.stopAnimation(animationStyle: .normal)
} else if( typeTextField.text == "DEF" && pickedCompanyField.text != "XYZ"){
// query
sender.startAnimation()
sender.stopAnimation(animationStyle: .shake)
// DispatchQueue.main.async {
self.resultLabel.text = "56.36"
// }
}
}
and I use the following subclass
import UIKit
class CpLabel: UILabel {
override public var canBecomeFirstResponder: Bool {
get {
return true
}
}
override init(frame: CGRect) {
super.init(frame: frame)
sharedInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
sharedInit()
}
func sharedInit() {
isUserInteractionEnabled = true
addGestureRecognizer(UILongPressGestureRecognizer(
target: self,
action: #selector(showMenu(sender:))
))
}
override func copy(_ sender: Any?) {
UIPasteboard.general.string = text
UIMenuController.shared.setMenuVisible(false, animated: true)
}
func showMenu(sender: Any?) {
becomeFirstResponder()
let menu = UIMenuController.shared
if !menu.isMenuVisible {
menu.setTargetRect(bounds, in: self)
menu.setMenuVisible(true, animated: true)
}
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return (action == #selector(copy(_:)))
}
}
I get this Thread Error ... I don't know what is causing it ? I have tried to use DispatchQue... function to see if the error regarding main thread stuff but it seems not ? SO Any? Help will be appreciated
Error screenshot:
thanks guys I found the issue ... It was declared as UILabel and its sub classed to CpLabel , So I changed the deceleration it to CpLabel and it worked..
I'm trying to figure out how to set the accessibility Increment/ Decrement of an UISlider with stepping. It keeps saying that the value is 0%, which it shouldn't. I also wonder if this is the reason why the accessibilityValue is not working..
ViewController
import UIKit
class RateAppViewController: UIViewController {
//MARK: IBOutlets
#IBOutlet weak var ratingSlider: UISlider!
let steps: Float = 0.2
override func viewDidLoad() {
super.viewDidLoad()
// UpdateUI
updateUI()
// InitalizeAccessibility
initalizeAccessibility()
}
private func updateUI() {
ratingSlider.value = 0.2
ratingSlider.minimumValue = 0.2
ratingSlider.maximumValue = 1.0
}
private func initalizeAccessibility() {
ratingSlider.isAccessibilityElement = true
ratingSlider.accessibilityTraits = UIAccessibilityTraitAdjustable
ratingSlider.accessibilityLabel = NSLocalizedString("Rating", comment: "RatingView Label")
ratingSlider.accessibilityIncrement()
ratingSlider.accessibilityDecrement()
}
override func accessibilityIncrement() {
ratingSlider.value += steps
setRating(ratingSlider.value)
}
override func accessibilityDecrement() {
ratingSlider.value -= steps
setRating(ratingSlider.value)
}
private func setRating(value: Float) {
let stars: Int = Int(value * 5)
print(stars)
if value == 0.2 {
ratingSlider.accessibilityValue = NSLocalizedString("1 star", comment: "One Star RatingSlider")
} else {
ratingSlider.accessibilityValue = NSLocalizedString("\(stars) Stars", comment: "Multiple Stars RatingSlider")
}
}
#IBAction func ratingValueChanged(sender: UISlider) {
let roundSteps = round(sender.value / steps) * steps
sender.value = roundSteps
}
}
I believe you need to subclass UISlider and implement the methods in that class.
So, my assignment for my class is to make an app for the 7th graders at my school to work on math.
In this particular view controller, I am making something that they can practice prime numbers with. I couldn't get everything to load using the override func viewDidLoad(){} so I implemented a button to activate the random number, modulus to check if it's prime, and insert it into the label.
This is ALL of my code that is inside of the Class:
#IBAction func primeBack(sender: UIButton) {
self.performSegueWithIdentifier("primeBack", sender: nil)
}
#IBOutlet var start: UIButton!
#IBOutlet var primeNum: UILabel!
var num = 1
var check = Double()
var temp2 = Double()
let lower : UInt32 = 1
let upper : UInt32 = 100
override func viewDidLoad() {
super.viewDidLoad()
primeNum.hidden = true
start.hidden = false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func start(sender: UIButton) {
primeNum.hidden = false
let temp1 = (arc4random_uniform(upper - lower) + lower)
primeNum.text = String(temp1)
while num <= 12
{
check = Double(temp1) / Double(num)
temp2 = check % 1
if temp2 == 0
{
num++
}
else
{
num = 12
}
}
start.hidden = true
}
#IBAction func prime(sender: UIButton) {
if temp2 == 0
{
self.performSegueWithIdentifier("primeCorrect", sender: nil)
}
else
{
self.performSegueWithIdentifier("primeIncorrect", sender: nil)
}
}
#IBAction func notPrime(sender: UIButton) {
if temp2 == 0
{
self.performSegueWithIdentifier("primeIncorrect", sender: nil)
}
else
{
self.performSegueWithIdentifier("primeCorrect", sender: nil)
}
}
Debug and watch what happens to your value of temp2. I suspect it never becomes equal to zero, hence your while loop never ends