Custom TextField layer / background / adapt using swift - swift

I would like to know if it's possible to create a custom background for a textfield using swift, for example expecting 4 letters, the textfield has 4 square. thx

Do you mean like this?
// Background
txtField.backgroundColor = UIColor.greenColor()
// Placeholder
txtField.placeholder = "1"
// Corner radius
txtField.layer.cornerRadius = 8
// A Boolean indicating whether sublayers are clipped to the layer’s bounds
txtField.layer.masksToBounds = true
UPDATE
Here is a method that will randomize a number and then create textfields according to the number that has been generated. You don´t need the random functionality of course if you already have a number. The only thing you have to do is change for var i = 0; i < rand; i++ rand to your variable. The textFieldEditingChanged function is the event when the users tries to add a new character to the textField and there is a check to only allow one character in each textField.
let rand = Int(arc4random_uniform(10) + 2)
for var i = 0; i < rand; i++ {
let myField: UITextField = UITextField (frame:CGRectMake(CGFloat(i * 30), 50, 25, 25));
myField.text = String(i)
myField.backgroundColor = UIColor.redColor()
myField.addTarget(self, action: "textFieldEditingChanged:", forControlEvents: UIControlEvents.EditingChanged)
self.view.addSubview(myField)
}
If you only have a String and you want to populate each char in a textField, you could do like this:
let word = "Car"
for var i = 0; i < word.characters.count; i++ {
let myField: UITextField = UITextField (frame:CGRectMake(CGFloat(i * 30), 50, 25, 25));
myField.text = String(word[word.startIndex.advancedBy(i)])
myField.backgroundColor = UIColor.redColor()
myField.addTarget(self, action: "textFieldEditingChanged:", forControlEvents: UIControlEvents.EditingChanged)
self.view.addSubview(myField)
}
Click event for the textField
func textFieldEditingChanged(target: UITextField){
if (target.text?.characters.count > 1){
target.text = target.text?.substringToIndex(target.text!.endIndex.predecessor())
}
}
UPDATE
To change responder
Declare a variable var tagNumber = 0 and when you loop through in your for statement and create your textFields just add this row to myField.tag = i. In your textFieldEditingChanged function, add this code block:
if (target.tag < tagNumber){
let nextTag: NSInteger = target.tag + 1;
// Try to find next responder
if let nextResponder: UIResponder! =
target.superview!.viewWithTag(nextTag){
nextResponder.becomeFirstResponder()
}
}

Related

Change background color of adjacent buttons in Swift

I want to change colors of all adjacent buttons in my UIStackView when any button is pressed. In the end I will turn this into an animation - almost like a ripple effect.
I looked at the Combine Framework but that seems to have too many unrelated features for what I need. Because the user could press any button, I don't think creating an observer for every button is an economical solution. I was hoping there was a way to find the adjacent view of a button's properties and influence that in some way?
Is there a simple solution to this problem, or do I need to build a complex matrix of IF statements, which is what I'm prepared to do in any case.
All my buttons are in a UIStackView (8 horizontal stack-views in 1 x vertical stack-view)
Here follows my non-ideal solution:
if sender.tag == 1 then {
view1.layer.backgroundColor = blue
view2.layer.backgroundColor = blue
view3.layer.backgroundColor = blue
} else if sender.tag == 2 then {
view4.layer.backgroundColor = blue
view5.layer.backgroundColor = blue
view6.layer.backgroundColor = blue
}...
You can find "adjacent" buttons by searching a 2-D array.
For example... if you have an 8x8 "grid" of buttons, you'll have 8 "rows" of 8 "columns". When you tap any button, search through the rows to find the row and column of the tapped button.
Suppose you find it at Row 4 : Col 4, then to find the adjacent buttons subtract and add a row and column in each direction:
// arrays are Zero based
// if tapped button is at
array[3][3]
// the button above it is at
array[3 - 1][3]
// the button to the left it is at
array[3][3 - 1]
// the button to the right it is at
array[3][3 + 1]
// the button below it is at
array[3 + 1][3]
If by adjacent you also want to include diagonals, you just need another set of "+/-" for "above and to the left" / "above and to the right" / "below and to the left" / "below and to the right":
Here's a complete example (code only... no #IBOutlet or #IBAction connections):
class ViewController: UIViewController {
// 2-D array to track the buttons
// we could use the stack views and their arrangedSubviews, but
// this will avoid repeated unwrapping of optionals
var arrayOfButtons: [[UIButton]] = []
// add a reset button above the grid
let resetBtn = UIButton()
// add a segmented control to select fully adjacent or diagonal
let segCtrl = UISegmentedControl(items: ["Full Only", "Include Diagonal"])
override func viewDidLoad() {
super.viewDidLoad()
// create an 8x8 "grid" of buttons
let outerStack = UIStackView()
outerStack.axis = .vertical
outerStack.distribution = .fillEqually
// we'll use Row:Col for the button labels
for row in 0..<8 {
var thisRow: [UIButton] = []
let rowStack = UIStackView()
rowStack.distribution = .fillEqually
for col in 0..<8 {
let b = UIButton()
b.backgroundColor = .blue
b.setTitle("\(row):\(col)", for: [])
b.setTitleColor(.white, for: .normal)
b.setTitleColor(.gray, for: .highlighted)
// add a border so we can see the frames
b.layer.borderWidth = 1.0
b.layer.borderColor = UIColor.yellow.cgColor
// square buttons
b.heightAnchor.constraint(equalTo: b.widthAnchor).isActive = true
// add button to rowStack
rowStack.addArrangedSubview(b)
// add button to 2-D array
thisRow.append(b)
// add target for button
b.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)
}
// add rowStack to outerStack
outerStack.addArrangedSubview(rowStack)
// add this row of buttons to 2-D array
arrayOfButtons.append(thisRow)
}
// outerStack properties
outerStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(outerStack)
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain outerStack width
outerStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 16.0),
outerStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -16.0),
// center vertically
outerStack.centerYAnchor.constraint(equalTo: g.centerYAnchor),
])
resetBtn.backgroundColor = .systemTeal
resetBtn.setTitle("Reset", for: [])
resetBtn.setTitleColor(.white, for: .normal)
resetBtn.setTitleColor(.gray, for: .highlighted)
resetBtn.addTarget(self, action: #selector(resetTapped(_:)), for: .touchUpInside)
[resetBtn, segCtrl].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
}
NSLayoutConstraint.activate([
resetBtn.bottomAnchor.constraint(equalTo: outerStack.topAnchor, constant: -20.0),
resetBtn.leadingAnchor.constraint(equalTo: outerStack.leadingAnchor),
resetBtn.trailingAnchor.constraint(equalTo: outerStack.trailingAnchor),
segCtrl.topAnchor.constraint(equalTo: outerStack.bottomAnchor, constant: 20.0),
segCtrl.leadingAnchor.constraint(equalTo: outerStack.leadingAnchor),
segCtrl.trailingAnchor.constraint(equalTo: outerStack.trailingAnchor),
])
segCtrl.selectedSegmentIndex = 0
}
#objc func resetTapped(_ sender: Any?) -> Void {
arrayOfButtons.forEach { thisRow in
thisRow.forEach { btn in
btn.backgroundColor = .blue
}
}
}
#objc func btnTapped(_ sender: Any?) -> Void {
guard let tappedBtn = sender as? UIButton else {
return
}
// find the row and column for the tapped button
var row: Int = -1
var col: Int = -1
for r in 0..<arrayOfButtons.count {
let thisRow = arrayOfButtons[r]
if let c = thisRow.firstIndex(of: tappedBtn) {
// found the tapped button
row = r
col = c
break
}
}
if row == -1 || col == -1 {
// did not find the tapped button in the grid!!!
return
}
// we found the row:col of the tapped button
var adjacentButtons: [UIButton] = [
tappedBtn
]
if segCtrl.selectedSegmentIndex == 0 {
// adjacent means ONLY above, left, right, below
if row > 0 {
// get button above
adjacentButtons.append(arrayOfButtons[row - 1][col])
}
if col > 0 {
// get button to the left
adjacentButtons.append(arrayOfButtons[row][col - 1])
}
if row < arrayOfButtons.count - 1 {
// get button below
adjacentButtons.append(arrayOfButtons[row + 1][col])
}
if col < arrayOfButtons[row].count - 1 {
// get button to the right
adjacentButtons.append(arrayOfButtons[row][col + 1])
}
} else {
// adjacent includes diagonals
if row > 0 {
// get button above and to the left
if col > 0 {
adjacentButtons.append(arrayOfButtons[row - 1][col - 1])
}
// get button above
adjacentButtons.append(arrayOfButtons[row - 1][col])
// get button above and to the right
if col < arrayOfButtons[row].count - 1 {
adjacentButtons.append(arrayOfButtons[row - 1][col + 1])
}
}
if col > 0 {
// get button to the left
adjacentButtons.append(arrayOfButtons[row][col - 1])
}
if col < arrayOfButtons[row].count - 1 {
// get button to the right
adjacentButtons.append(arrayOfButtons[row][col + 1])
}
if row < arrayOfButtons.count - 1 {
// get button below and to the left
if col > 0 {
adjacentButtons.append(arrayOfButtons[row + 1][col - 1])
}
// get button below
adjacentButtons.append(arrayOfButtons[row + 1][col])
// get button below and to the right
if col < arrayOfButtons[row].count - 1 {
adjacentButtons.append(arrayOfButtons[row + 1][col + 1])
}
}
}
adjacentButtons.forEach { btn in
btn.backgroundColor = .red
}
}
}

Will this statement always evaluate to nil in Swift?

open var buttonInit: ((_ index: Int) -> UIButton?)?
...
if let button: UIButton = self.buttonInit?(i) {
finButton = button
}else {
let button = UIButton(type: .custom)
button.setTitleColor(button.tintColor, for: [])
button.layer.borderColor = button.tintColor.cgColor
button.layer.borderWidth = 1
button.layer.cornerRadius = buttonHeight/2
finButton = button
}
I don't find any function description about buttonInit in AZDialogViewController. Does it mean button: UIButton = self.buttonInit?(i) will always be nil and finButton = button will not be executed?
The latter part of the code you quoted is in the setUpButton method:
fileprivate func setupButton(index i:Int) -> UIButton{
if buttonHeight == 0 {buttonHeight = CGFloat(Int(deviceHeight * 0.07))}
let finButton: UIButton
if let button: UIButton = self.buttonInit?(i) {
finButton = button
}else {
let button = UIButton(type: .custom)
button.setTitleColor(button.tintColor, for: [])
button.layer.borderColor = button.tintColor.cgColor
button.layer.borderWidth = 1
button.layer.cornerRadius = buttonHeight/2
finButton = button
}
This method is called here:
open func addAction(_ action: AZDialogAction){
actions.append(action)
if buttonsStackView != nil{
let button = setupButton(index: actions.count-1)
self.buttonsStackView.addArrangedSubview(button)
//button.frame = buttonsStackView.bounds
button.center = CGPoint(x: buttonsStackView.bounds.midX,y: buttonsStackView.bounds.maxY)
animateStackView()
}
}
From this we can see that buttonInit seems to be used to let the user of the library specify what kind of button they want as the action buttons. Another piece of evidence is that buttonInit is declared open, so it is likely that it is the client code who should set this, not the AZDialogViewController.
Plus, the README file showed this usage:
Use custom UIButton sub-class:
dialog.buttonInit = { index in
//set a custom button only for the first index
return index == 0 ? HighlightableButton() : nil
}
So to answer your question, the if branch will be executed if you set buttonInit.
#Huwell,
the documentation in the repository states to initialize the button in the following manner:
dialog.buttonInit = { index in
//set a custom button only for the first index
return index == 0 ? HighlightableButton() : nil
}
The button should be part of your DialogViewController.

total of label click on two buttons

I have two UIButton if I click onto button1 the value of label1 is 250, if I click again onto button1 the value of label1 should be 0. The same logic is applied to my button2 and label2. I want to store the addition of label1 and label2 into label3. . My code is:
func PickUpCarCost() {
if (!isclick){
imgCheck.image = UIImage(named: "check.png")
isclick=true
//Pickup fare conver into integer
let PickUp = String(self.PickUpPrice)
PickUpFare.text = PickUp
self.pickCost = Int( PickUpFare.text!)
self.PAyAmount = ((self.PayFareWithSecurity)+(self.pickCost))
print("PaybleAmount: \(self.PAyAmount)")
self.AmountPay1 = ((self.PAyAmount)+(self.DeliverCost))
PaybleAmount.text=String(self.AmountPay1!)
}
else
{
imgCheck.image = UIImage(named: "uncheck.png")
PickUpFare.text = "0"
self.PickUpElse=Int(PickUpFare.text!)
print("PickUpElse: \(self.PickUpElse)")
self.PAyAmount = (self.PayFareWithSecurity)+(self.PickUpElse)
PaybleAmount.text=String(self.PAyAmount!)
isclick=false
}
}
func CarDeliverCost() {
if (!isclick){
imgUnCheck.image = UIImage(named: "check.png")
isclick=true
let DeliverPrice = String(self.deliveryPrice)
DeliverFare.text = DeliverPrice
self.DeliverCost = Int(DeliverFare.text!)
self.PAyAmount = ((self.PayFareWithSecurity)+(self.DeliverCost))
print("PaybleAmount: \(self.PAyAmount)")
PaybleAmount.text=String(self.PAyAmount!)
}
else
{
imgUnCheck.image = UIImage(named: "uncheck.png")
let deliveryelse = String(0)
DeliverFare.text = deliveryelse
self.deliver = Int(DeliverFare.text!)
PaybleAmount.text=String(self.PAyAmount!)
isclick=false
}
}
The first issue that you're facing is that you are using the same boolean isClick for two different scenarios. Your logic is that the user could decide to click onto both buttons or a single one. So if I click onto the first button then your flag is turn on, since the second button also uses the same boolean then you'll get that uncheck behavior automatically.
Thus you should use two different booleans such as hasPressOntoFirstButton and hasPressOntoSecondButton, where both set to false at the beginning, and each variable is used in their respective scene.
You mentioned that you want to add the label1 to label2, the easier way would be add the variable that set these labels. i.e
let label1 = UILabel()
let label2 = UILabel()
let label3 = UILabel()
let data1: Double = 83.0
let data2: Double = 82.0
var total: Double { // have a computed variable to adds automatically
return data1 + data2
}
label1.text = "\(data1)"
label2.text = "\(data2)"
label3.text = "\(data1 + data2)" // or "\(total)"
Remarks:
(1) your naming convention are really misleading, you should separate UI object naming from data. i.e you can have deliveryFareLabel.text instead of DeliverFare.text
(2) avoid using !, unwrapped all optional using either nil coalescing ??, or if let or guard statements

Storing UIView with children

Im working on a 2x2 grid with everyone of them having a UIView and a child label with text and background color.
I generate the UIView with a for loop like this:
// Generatin answer cube buttons
for var i = 0; i < cubeCount; i++
{
// two answers case
if(cubeCount < 3)
{
var btn = button(xpos, y: ypos, width: screenWidth, height: (screenHeight * 2));
var lbl = labelis("\(i)", btn: btn)
btn.addSubview(lbl)
xpos = xpos + (screenWidth + 10);
self.view.addSubview(btn);
}
// 3+ answers case
else
{
var btn = button(xpos, y: ypos, width: screenWidth, height: screenHeight);
var lbl = labelis("\(i)", btn: btn)
btn.addSubview(lbl)
xpos = xpos + (screenWidth + 10)
self.view.addSubview(btn)
// change row in case of more than 2 answers
if(i == 1)
{
xpos = 20
ypos = ypos + (screenHeight + 10)
}
}
I also have a tapGesture function letting me know when I click on one of the answer cube.
My problem here is that, when clicking on one of the cube, I would like to access all the cubes and change their label's background color.
I though about storing the UIView into an array so I could act on them from the tapGesture function, but I don't see how I could make this work.
I though that maybe someone could guide me through the way of dealing with this.
thanks.
In the click handler of cube button try following code:
for subview in view.subviews as [UIView] {
if let cubeButton = subview as? button {
//Do something with this cubeButton here.
}
}
So I've found a solution to my problem so I answer my own question for people who might look into this in the future:
I've created an array:
var answerData:[UIView] = [];
and added my UIView along the way for those I wanted to keep stored
var uiviewvariable = UIView()
answerData.append(uiviewVariable)
then, on my tapGesture function, when the user tap one of the view, I can call for the array and use act on the UIViews
// Accessing stored UIView
for(var i = 0; i < answerData.count; i++){
// Accessing subviews
for subview in answerData[i].subviews as [UIView]
{
if subview.tag == 0
{
if let label = subview as? UILabel {
// do something with label inside the views
}
}
}
}
for some reason I use something similar than Abdullah's answer for selecting my labels but I didn't managed to make his snippet work.

how to create multiple UIButton on viewDidLoad (Swift)

I'm sorry but if I have a number of buttons that comes from a plist file ...
how do I re-create all the buttons?
Example I tried in this way :
func loadSavedButtons() {
// I extract the number from the plist file
var number: AnyObject? = data.valueForKey("NumberOfButton")
var someNumb: Int = ("\(number!)").toInt()!
if (someNumb != 0) {
self.countButton = someNumb
for (var i=0; i < someNumb; i++) {
In This Point I should do
var newButton6: () = CreateButtonWithIndex(i)
self.view.addSubview(newButton6)
}}}
and
#IBAction func CreateButtonWithIndex(sender: AnyObject){
let button = UIButton.buttonWithType(UIButtonType.System) as UIButton
ecc…
self.view.addSubview(button)
but don't go ... i don't have all save button please help me !!!
In your function
Change the following
let button = UIButton.buttonWithType(UIButtonType.System) as UIButton
to
var button = UIButton.buttonWithType(UIButtonType.System) as UIButton
then after
self.view.addSubview(button)
add the following:
button = UIButton.new()