Move cursor in uitextfield 3 space to the right - ios

How to move and show cursor 3 spaces to the right in uitextfield when i click on uitextfield. I make uitextfield rounded corner and put constraints left "10" from main.storyboard and when i click on uitextfield the cursor shows outside of uitextfield. Below is the swift code.
#IBOutlet weak var txtSearch: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
txtSearch.layer.cornerRadius = 22
txtSearch.clipsToBounds = true
txtSearch.layer.borderWidth = 2.0
txtSearch.borderStyle = .none
}

To achieve this you'll need to create a custom UITextField by subclassing the standard object and then overrding the functions that set the boundary (i.e. inset) of the content. You'll need to work in points, not characters, so play with the inset variables to get the look you want.
class MyTextField: UITextField {
var insetX: CGFloat = 20
var insetY: CGFloat = 0
override func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: insetX , dy: insetY)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: insetX , dy: insetY)
}
}
You will need to set the class of the textfield in IB to be your custom class.

Related

Changing class in a UIView (Swift)

I would like to use a button to toggle the contents of a UIView.
I set up two classes, graphClass1 and graphClass2. (The button is in the topView.)
When I click the button, I get the "my button" message from debugPrint, but I don't get the debugPrint messages from within the classes. So, I added setNeedsDisplay but that did not help.
(This is a simplified version - there are actually a lot more classes - which is why I am trying to reuse the same view instead of just creating two separate views.)
how do I get the appropriate class to display in the view?
because graphClass1 creates additional subviews when I toggle back and forth, will the number of graphClass1's subviews just keep growing? If so, how do I remove them when leaving? (I know that self.layer.sublayers = nil or textView.removeAll() would leave them until returning - if they even remove them at all.)
in the button toggle, rather than use a Bool to test which graph, I'd prefer something more intuitive like if currentGraph == GraphClass1 but this gives me the error message: Binary operator '==' cannot be applied to operands of type 'UIView' and 'GraphClass1.Type'. How would do I fix this?
class ViewController: UIViewController {
#IBOutlet var topView: UIView!
#IBOutlet var bottomView: UIView!
#IBOutlet var myButton: UIButton!
var graph1: Bool = true
var currentView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
bottomView = GraphClass1()
setConstraints()
}
#IBAction func myButton(_ sender: Any) {
debugPrint("my button")
if graph1 {
currentView.removeFromSuperview()
currentView = GraphClass2()
cv2.addSubview(currentView)
graph1 = false
}
else {
currentView.removeFromSuperview()
currentView = GraphClass1()
cv2.addSubview(currentView)
graph1 = true
}
cv2.setNeedsDisplay()
}
}
class GraphClass1: UIView {
var textView = UITextView()
override func draw(_ rect: CGRect) {
super.draw(rect)
self.layer.sublayers = nil
textView.removeAll()
createTextView()
debugPrint("inside GraphClass1")
}
func createTextView() {
textView = UITextView(frame: CGRect(x: 8, y: 8, width: 300, height: 100))
textView.text = "Test, this is only a test"
textView.textAlignment = .center
textView.font = UIFont(name: "Courier", size: 16)
textView.backgroundColor = .orange
self.addSubview(textView)
}
}
class GraphClass2: UIView {
override func draw(_ rect: CGRect) {
super.draw(rect)
debugPrint("inside GraphClass2")
}
}
Instead of changing the UIView() to a GraphClass(), you should add GraphClass() to bottomView() as a subview. To switch out GraphClass1(), you would remove it from bottomView() and set up GraphClass2() as the subview of bottomView(). Removing a view also removes all its subviews.
First, create a bottomView in interface builder, just like the top view. It will be like a place holder. You will have;
#IBOutlet var bottomView: UIView!
In viewDidLoad, you add the specific view as needed with
bottomView.addSubView(myInstanceOfAGraphView.view)
myInstanceOfAGraphView.didMove(toParent: bottomView)
I would create view controllers for each graph view and switch them as needed.
When you need to change, remove its view with;
myInstanceOfAGraphView.view.removeFromSuperview()

setNeedsDisplay() is not calling draw(_ rect: CGRect)

I found similar questions in this website but none of them solved my issue. Please carefully read the whole code. The setNeedsDisplay() function is not calling the draw(_ rect: CGRect) when I want to draw a line on MyView.
I created a view called "myView" in storyboard as sub View of "MyViewController" and created a IBOutlet to the view controller.
Then I created a class called "MyViewClass" and set it as the class of "myView" in storyboard.
I set the bool value drawLine to true and call function updateLine(),
the problem is the setNeedsDispaly() is not triggering the draw(_ rect: CGRect) function.
import UIKit
class MyViewClass : UIView{
var drawLine = Bool() // decides whether to draw the line
func updateLine(){
setNeedsDisplay()
}
override func draw(_ rect: CGRect) {
if drawLine == true{
guard let context = UIGraphicsGetCurrentContext() else{
return
}
context.setLineWidth(4.0)
context.setStrokeColor(UIColor.red.cgColor)
context.move(to: CGPoint(x: 415 , y: 650))
context.addLine(to: CGPoint(x:415 , y: 550))
context.strokePath()
}
}
}
class myViewController:UIViewController {
#IBOutlet weak var insideView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let myViewInstance = MyViewClass()
myViewInstance.drawLine = true
myViewInstance.updateLine()
}
}
I'm fairly new to Swift. Any help will appreciated. Thanks.
You have 2 issues:
you're not giving the new view a frame so it defaults to zero width and zero height
you're not adding the view to the view heirarchy
let myViewInstance = MyViewClass(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height))
myViewInstance.backgroundColor = .white // you might want this a well
myViewInstance.drawLine = true
self.view.addSubview(myViewInstance)
myViewInstance.updateLine()
A cleaner way to have your view redraw when a property (such as drawLine) is changed is to use a property observer:
var drawLine: Bool = true {
didSet {
setNeedsDisplay()
}
}
That way, the view will automatically redraw when you change a property and then you don't need updateLine().
Note that setNeedsDisplay just schedules the view for redrawing. If you set this on every property, the view will only redraw once even if multiple properties are changed.
Note: viewDidLoad() would be a more appropriate place to add your line because it is only called once when the view is created. viewWillAppear() is called anytime the view appears so it can be called multiple times (for instance in a UITabView, viewWillAppear() is called every time the user switches to that tab).
MyView class
class myView : UIView {
var updateView : Bool = false {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
print("in Draw")
}
}
MyViewController
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let view = myView()
view.updateView = true
}
}
In the storyboard i had setup the view class as myView therefore its visible.
Hopefully this will help you.

Using scroll view programmatically

I am trying to develop an app with the UI created only programmatically.
I want to create a simple view which is a UIScrollView (to be able to scroll the view when the keyboard is appearing) with a containerView (UIView) where we can find a button.
I am using PureLayout to make easier the set up of constraints, swift 4, Xcode 9.2 beta
Below the class of this view
class SimpleView: UIScrollView {
var containerView: UIView!
var signInButton: UIButton!
var signInLabel: UILabel!
var screenSize: CGSize = CGSize.zero
var shouldSetupConstraints = true
override init(frame: CGRect) {
super.init(frame: frame)
self.screenSize = frame.size
self.containerView = UIView(frame: CGRect.zero)
self.signInButton = UIButton(frame: CGRect.zero)
self.signInLabel = UILabel(frame: CGRect.zero)
self.addSubview(self.containerView)
self.containerView.addSubview(self.signInButton)
self.signInButton.addSubview(self.signInLabel)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func updateConstraints() {
if(shouldSetupConstraints) {
self.layoutSignInButton()
self.layoutSignInLabel()
shouldSetupConstraints = false
}
super.updateConstraints()
}
private func layoutContainerView() {
self.containerView.autoPinEdgesToSuperviewEdges()
self.containerView.backgroundColor = UIColor.yellow
}
private func layoutSignInButton() {
self.signInButton.autoPinEdge(toSuperviewEdge: .right)
self.signInButton.autoPinEdge(toSuperviewEdge: .left)
self.signInButton.autoPinEdge(toSuperviewEdge: .top)
self.signInButton.autoSetDimension(.height, toSize: 55.0)
self.signInButton.backgroundColor = UIColor(hex: "#FD9FA2")
}
private func layoutSignInLabel() {
self.signInLabel.autoPinEdgesToSuperviewEdges()
self.signInLabel.shadowColor = UIColor(hex: "#9A615E")
self.signInLabel.shadowOffset = CGSize(width: 0.0, height: 2)
self.signInLabel.text = NSLocalizedString("SIGN IN", comment: "")
self.signInLabel.textAlignment = .center
self.signInLabel.textColor = UIColor.white
self.signInLabel.font = UIFont.boldSystemFont(ofSize: 15.0)
self.signInLabel.backgroundColor = UIColor.clear
}
}
Below the code of the UIViewController subclass embedding the previous view
class SignInViewController: UIViewController {
var simpleView: SimpleView!
override func viewDidLoad() {
super.viewDidLoad()
self.simpleView = SimpleView(frame: self.view.bounds) // with SimpleView(frame: self.view.frame) has the same behaviour
self.view.addSubview(self.simpleView)
self.simpleView.autoPinEdgesToSuperviewEdges()
self.navigationController?.navigationBar.isHidden = true
}
}
Unfortunatly the result is not the one expected : see below
What am I missing ?
Different points are missing:
- The position of the button is weird (space between the button and the top / left side of the button partly hidden outside of the screen)
- the container view is invisible (backgroundColor = UIColor.yellow has no effect)
Thank you by advance !
//////////////////////////// EDIT ////////////////////////////////
Below a screenshot of the exact same code using a UIView instead of UIScrollView
Class SimpleView: UIView {
enter image description here
The content of a UIScrollView must also define the .contentSize` of the scroll view.
I don't use PureLayout, so I don't know what the syntax is, but in your layoutContainerView() func, you need to also do:
self.containerView ... set width dimension to SuperviewWdith
That will set the content of containerView to the width of the scroll view, and that should fix the width part.
I assume you will be adding elements to containerView and set their constraints to control the height of it.

Swift IOS transparent view over original view. Overlay. Subview

I can use the following code to override drawRect() in swift, which works fine.
override func drawRect(rect: CGRect) {
var path = UIBezierPath(ovalInRect: rect)
UIColor.greenColor().setFill()
path.fill()
}
I want to add subview(or second view) over the original view.
var overlayView = UIView()
self.view.addSubview(overlayView)
My question is, how can I override the drawRect() of a subview?
Or, how can I just make the subview a new view instead and place it over the original view?
Create a custom UIView subclass, e.g.
class MyCustomView: UIView {
override func drawRect(rect: CGRect) {
// do whatever you need to do
}
}
Then replace var overlayView = UIView() with var overlayView = MyCustomView()

How to access the value of a UIStepper inside a Cocoa Touch Class

I'm trying to create a custom slider, using a cocoa touch class, whose maximum value is determined by a UIStepper. I have the UIStepper wired to my view controller and I want to reference its value inside the cocoa touch class as the slider's maximum value. What is the syntax for referencing the stepper's value inside the class?
I keep getting the error use of unresolved identifier.
Here is my viewController:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var stepperValue: UIStepper!
#IBOutlet weak var label: UILabel!
let slider1 = Slider1(frame: CGRectZero)
override func viewDidLoad() {
super.viewDidLoad()
label.textColor = UIColor.darkTextColor()
slider1.backgroundColor = UIColor.lightGrayColor()
view.addSubview(slider1)
}
override func viewDidLayoutSubviews() {
let margin: CGFloat = 20.0
let width = view.bounds.width - 2 * margin
slider1.frame = CGRect(x: margin, y: 3 * margin, width: width, height: 1.5 * margin)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Here is my UIControl subclass:
class Slider1: UIControl {
var minimumValue = 0.0
var maximumValue = stepperValue.value
var value = 0
let trackLayer = CALayer()
var trackHeight:CGFloat = 2.0
var trackColor = UIColor.blackColor().CGColor
var tickHeight:CGFloat = 8.0
var tickWidth: CGFloat = 2.0
var tickColor = UIColor.blackColor().CGColor
let thumbLayer = CALayer()
var thumbColor = UIColor.blackColor().CGColor
var thumbMargin:CGFloat = 2.0
var thumbWidth: CGFloat {
return CGFloat(bounds.height)
}
}
If you want a slider, use a slider. You will have a LOT of work to do if you want to create your own slider-like control starting from UIControl.
Just make your view controller drive everything.
Have the value changed event on your stepper trigger an action in the view controller.
In that stepperValueChanged action, fetch the new value of the stepper and use it to change the maximum value of the slider. That's all there is to it.

Resources