Extension causing issue with clear button in Swift - ios

I'm using a placeHolder extension to give padding to the placeholder. But when I apply this class to my input field it doesn't show the clear button even if I select "Appears while editing" on the storyboard.
Can someone tell me how to fix it?
import UIKit
class textFiledplaceholder: UITextField {
static let font_size : CGFloat = 16
static let leftPadding : CGFloat = 15
static let righPadding : CGFloat = 15
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.comminIt()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.comminIt()
}
func comminIt()
{
borderStyle = .none
backgroundColor = .white
// layer.masksToBounds = true
setLeftPaddingPoints(textFiledplaceholder.leftPadding)
setRightPaddingPoints(textFiledplaceholder.righPadding)
}
}
extension UITextField {
func setLeftPaddingPoints(_ amount:CGFloat){
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.frame.size.height))
self.leftView = paddingView
self.leftViewMode = .always
}
func setRightPaddingPoints(_ amount:CGFloat) {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: amount, height: self.frame.size.height))
self.rightView = paddingView
self.rightViewMode = .always
}
}

You can not use rightview and clearbutton together. And if you are going to use a clear button then I don't think there is any use of right padding. Remove right padding and it will resolve your issue.

Related

when using CHTWaterfallLayout ,In My collection view cell , subview is not placing properly specially Y co-ordinate.scrolling makes it worse

this is the code where i am configuring the cell.
cell.configure(image: models[indexPath.item].image, tagText: models[indexPath.item].tag, priceIcon: models[indexPath.item].priceIcon, value: models[indexPath.item].price)
and this is my code for cell.
//
// ImageCollectionViewCell.swift
// tr0ve-iOSApp
//
//
//
// ImageCollectionViewCell.swift
// MyCollectionView
//
import UIKit
class ImageCollectionViewCell: UICollectionViewCell {
static let identifier = "ImageCollectionViewCell"
let itemView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(itemView)
contentView.clipsToBounds = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
itemView.frame = contentView.bounds
}
override func prepareForReuse() {
super.prepareForReuse()
itemView.subviews.forEach { view in
view.removeFromSuperview()
}
}
func configure (image: UIImage?, tagText: String, priceIcon: UIImage, value: Float){
let imageView = UIImageView(image: image)
let priceTagView = UIView(frame: CGRect(x: 5, y: contentView.frame.size.height-50, width: 60, height: 20))
priceTagView.backgroundColor = .black
let valueLabel = UILabel(frame: CGRect(x: 20, y: 5, width: 35, height: 10))
valueLabel.textColor = .white
valueLabel.text = String(value)
valueLabel.font = UIFont.systemFont(ofSize: 12, weight: .regular)
let priceIconView = UIImageView(frame: CGRect(x: 5, y: 5, width: 10, height: 10))
priceIconView.image = priceIcon
priceTagView.addSubview(priceIconView)
priceTagView.addSubview(valueLabel)
let tag = UILabel(frame: CGRect(x: 100, y: contentView.frame.size.height-50, width: 20, height: 20))
tag.text = tagText
tag.textColor = .white
tag.textAlignment = .center
if tagText == "UC" {
tag.backgroundColor = .green
}
else {
tag.backgroundColor = .blue
}
itemView.addSubview(imageView)
itemView.addSubview(priceTagView)
itemView.addSubview(tag)
}
}
[in this image i want to add subview in cell's bottom, and in tried it using image's frame and by contentView's frame. but it is doing good for some cells and bad for the other ones. and when i scroll everyhing meshes up.1

addTarget on a Custom UI Button not working programmatically

I created a custom UIButton with this initialiser :
class CustomButton : UIButton{
override init(frame: CGRect) {
super.init(frame: frame)
setUpButtoninClass(frame)
addTarget(self, action: #selector(handleTap), for:.touchUpInside )
}
fileprivate func setUpButtoninClass(_ frame: CGRect) {
let padding : CGFloat = 16
self.frame = frame
layer.shadowColor = UIColor.darkGray.cgColor
layer.shadowOpacity = 0.3
layer.shadowOffset = .zero
layer.shadowRadius = 10
layer.cornerRadius = frame.width/2
backgroundColor = UIColor(white: 0.9, alpha: 1)
let buttonView = UIView(frame: frame)
buttonView.layer.cornerRadius = frame.width/2
buttonView.backgroundColor = .white
addSubview(buttonView)
let imageView = UIImageView(image: UIImage(named: "pen")?.withRenderingMode(.alwaysTemplate))
imageView.tintColor = UIColor(white: 0.7, alpha: 1)
buttonView.addSubview(imageView)
imageView.anchor(top: buttonView.topAnchor, leading: buttonView.leadingAnchor, bottom: buttonView.bottomAnchor, trailing: buttonView.trailingAnchor, padding: UIEdgeInsets.init(top: padding, left: padding, bottom: padding, right: padding))
}
#objc func handleTap(){
print("I'm here")
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}}
In the initialiser I'm adding a target but when I actually initialise the custom button in the VC the #selector method (handleTap) is not called.
This is the implementation of custom Button in VC:
class ViewController: UIViewController {
let circularButton = CustomButton(frame: CGRect(x: 0, y: 0, width: 70, height: 70))
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(circularButton)
circularButton.center = view.center
}
I also tried to add the target when initialising the CustomButton in the VC but nothing changed.
I would like to know where I'm making a mistake in setting up the button.
EDIT 1 :
this is the Debug View Hierarchy
OMG, after debug your code, buttonView and imageView is on the top. Button is behide. You can set the color to debug it more easily. Delete 2 views above make your code works perfectly
I think it's your fault here,
Touch is not detected because you added an ImageView to the top of UIButton.
Try this, or this one,
buttonView.isUserInteractionEnabled = true
imageView.isUserInteractionEnabled = true

How can I create dynamic labels using UIStackView

I have 10 UILabels with different sizes, and I want to arrange them in 3 rows, and all rows have leading alignment, and if the last item of each row can't fit in remaining space of parent view, it have to move to the next line. How can I do that by using UIStackview?
You can try to do something like that:
Your ViewController
for item in array {
let someView = VPView(frame: CGRect(x: 0, y: 0, width: 70, height: 20))
someView.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(someView)
}
UIView Class:
class VPView: UIView {
let myLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
self.addLabel()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func addLabels() {
//Mark: - Styles
let labelH: CGFloat = 15
let labelW: CGFloat = 70
//MARK: - My Label
self.myLabel.frame = CGRect(x: 0, y: 0, width: labelW, height: labelH)
self.myLabel.backgroundColor = UIColor.blue
self.myLabel.textAlignment = NSTextAlignment.center
self.myLabel.numberOfLines = 0
self.addSubview(self.myLabel)
self.myLabel.translatesAutoresizingMaskIntoConstraints = false
self.myLabel.heightAnchor.constraint(equalToConstant: labelH).isActive = true
self.myLabel.widthAnchor.constraint(equalToConstant: labelW).isActive = true
self.myLabel.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
self.myLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
}
}

How to create custom view programmatically in swift having controls text field, button etc

I am trying to access the MyCustomView from another class using the following code in ViewController.swift ..
var view = MyCustomView(frame: CGRectZero)
.. in the viewDidLoad method. The problem is the view does not get initialized in the simulator.
I have already set class in storyboard for the current ViewController.
class MyCustomView: UIView {
var label: UILabel = UILabel()
var myNames = ["dipen","laxu","anis","aakash","santosh","raaa","ggdds","house"]
override init(){
super.init()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.addCustomView()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addCustomView() {
label.frame = CGRectMake(50, 10, 200, 100)
label.backgroundColor=UIColor.whiteColor()
label.textAlignment = NSTextAlignment.Center
label.text = "test label"
label.hidden=true
self.addSubview(label)
var btn: UIButton = UIButton()
btn.frame=CGRectMake(50, 120, 200, 100)
btn.backgroundColor=UIColor.redColor()
btn.setTitle("button", forState: UIControlState.Normal)
btn.addTarget(self, action: "changeLabel", forControlEvents: UIControlEvents.TouchUpInside)
self.addSubview(btn)
var txtField : UITextField = UITextField()
txtField.frame = CGRectMake(50, 250, 100,50)
txtField.backgroundColor = UIColor.grayColor()
self.addSubview(txtField)
}
The CGRectZero constant is equal to a rectangle at position (0,0) with zero width and height. This is fine to use, and actually preferred, if you use AutoLayout, since AutoLayout will then properly place the view.
But, I expect you do not use AutoLayout. So the most simple solution is to specify the size of the custom view by providing a frame explicitly:
customView = MyCustomView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
self.view.addSubview(customView)
Note that you also need to use addSubview otherwise your view is not added to the view hierarchy.
Swift 3 / Swift 4 Update:
let screenSize: CGRect = UIScreen.main.bounds
let myView = UIView(frame: CGRect(x: 0, y: 0, width: screenSize.width - 10, height: 10))
self.view.addSubview(myView)
var customView = UIView()
#IBAction func drawView(_ sender: AnyObject) {
customView.frame = CGRect.init(x: 0, y: 0, width: 100, height: 200)
customView.backgroundColor = UIColor.black //give color to the view
customView.center = self.view.center
self.view.addSubview(customView)
}
let viewDemo = UIView()
viewDemo.frame = CGRect(x: 50, y: 50, width: 50, height: 50)
self.view.addSubview(viewDemo)
view = MyCustomView(frame: CGRectZero)
In this line you are trying to set empty rect for your custom view. That's why you cant see your view in simulator.

Custom Clear Button

I want to create custom clear button on UITextField, that is to use rightView and put image there, the problem is attaching the original clear button event to that custom rightView.
In Objective-C i can do that this way:
SEL clearButtonSelector = NSSelectorFromString(#"clearButton");
// Reference clearButton getter
IMP clearButtonImplementation = [self methodForSelector:clearButtonSelector];
// Create function pointer that returns UIButton from implementation of method that contains clearButtonSelector
UIButton * (* clearButtonFunctionPointer)(id, SEL) = (void *)clearButtonImplementation;
// Set clearTextFieldButton reference to “clearButton” from clearButtonSelector
UIButton *_clearTextFieldButton = clearButtonFunctionPointer(self, clearButtonSelector);
[_clearTextFieldButton setImage:[UIImage imageNamed:#"icon_remove"] forState:UIControlStateNormal];
self.hasClearButtonAsRightView = YES;
now how to convert this to Swift?
or any ideas to workaround it?
You can add a custom button as right view of the UITextField like this
class CustomTextField : UITextField
{
override init(frame: CGRect) {
super.init(frame: frame)
let clearButton = UIButton(frame: CGRect(origin: .zero, size: CGSize(width: 15, height: 15))
clearButton.setImage(UIImage(named: "clear.png")!, forState: UIControlState.Normal)
self.rightView = clearButton
clearButton.addTarget(self, action: "clearClicked:", forControlEvents: .touchUpInside)
self.clearButtonMode = .never
self.rightViewMode = .always
}
func clearClicked(sender: UIButton)
{
self.text = ""
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Implementing a custom text field as suggested in the other answers is not a good idea. You should try to use extensions rather than inheritance if at all possible, because with inheritance you are much more likely to need to make major changes to your codebase in response to changes, whereas using extensions you are much more flexible to change.
I strongly suggest that instead of implementing a custom text field, you extend the UITextField class like this:
extension UITextField {
func applyCustomClearButton() {
clearButtonMode = .Never
rightViewMode = .WhileEditing
let clearButton = UIButton(frame: CGRectMake(0, 0, 16, 16))
clearButton.setImage(UIImage(name: "iCFieldClear")!, forState: .Normal)
clearButton.addTarget(self, action: "clearClicked:", forControlEvents: .TouchUpInside)
rightView = clearButton
}
func clearClicked(sender:UIButton) {
text = ""
}
}
Then to use it you just do this:
yourTextField.applyCustomClearButton()
Here is my solution in Swift 3. In addition to the already existing answer, I also made sure that both left and right views of the textfield (i.e. the search magnifier image view and the custom clear button) have a padding to their left/right by overriding leftViewRect() and rightViewRect(). Otherwise, they will stick right on the edges of the textfield.
class CustomTextField: UITextField
{
fileprivate let searchImageLength: CGFloat = 22
fileprivate let cancelButtonLength: CGFloat = 15
fileprivate let padding: CGFloat = 8
override init( frame: CGRect )
{
super.init( frame: frame )
self.customLayout()
}
required init?( coder aDecoder: NSCoder )
{
super.init( coder: aDecoder )
self.customLayout()
}
override func leftViewRect( forBounds bounds: CGRect ) -> CGRect
{
let x = self.padding
let y = ( bounds.size.height - self.searchImageLength ) / 2
let rightBounds = CGRect( x: x, y: y, width: self.searchImageLength, height: self.searchImageLength )
return rightBounds
}
override func rightViewRect( forBounds bounds: CGRect ) -> CGRect
{
let x = bounds.size.width - self.cancelButtonLength - self.padding
let y = ( bounds.size.height - self.cancelButtonLength ) / 2
let rightBounds = CGRect( x: x, y: y, width: self.cancelButtonLength, height: self.cancelButtonLength )
return rightBounds
}
fileprivate func customLayout()
{
// Add search icon on left side
let searchImageView = UIImageView()
searchImageView.contentMode = .scaleAspectFit
let searchIcon = UIImage( named: "search_magnifier" )
searchImageView.image = searchIcon
self.leftView = searchImageView
self.leftViewMode = .always
// Set custom clear button on right side
let clearButton = UIButton()
clearButton.setImage( UIImage( named: "search_cancel" ), for: .normal )
clearButton.contentMode = .scaleAspectFit
clearButton.addTarget( self, action: #selector( self.clearClicked ), for: .touchUpInside )
self.rightView = clearButton
self.clearButtonMode = .never
self.rightViewMode = .whileEditing
}
#objc fileprivate func clearClicked( sender: UIButton )
{
self.text = ""
}
}
with iOS 14, none of the solution were working for me. the clear button was getting wrong offset for different device sizes.
I had the image. if you dont have it, you can download it from SF Symbols. the name is xmark.circle.fill
In the end, I used this
let customClearButton = UIButton.appearance(whenContainedInInstancesOf: [UITextField.self])
customClearButton.setImage(UIImage(named: "icon-x"), for: .normal)
Updated to Swift 5, based on #marmoy answer:
public func addClearAllCustomButton() {
clearButtonMode = .never
rightViewMode = .whileEditing
let clearButton = UIButton(frame: rightViewRect(forBounds: bounds))
clearButton.setImage(UIImage(named: "clearAll"), for: .normal)
clearButton.addTarget(self, action: #selector(didTouchClearAllButton(sender:)), for: .touchUpInside)
rightView = clearButton
}
public func removeClearAllButton() {
rightViewMode = .never
}
#objc func didTouchClearAllButton(sender: UIButton) {
text = ""
}
For rigth padding & listen the clear delegate of textfield
class SearchBoxTextField: UITextField {
override open func awakeFromNib() {
super.awakeFromNib()
self.initialize()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func initialize() {
let clearButton = UIButton(frame: CGRect(x: 0, y: 0, width: 12, height: 12))
clearButton.setImage(UIImage(named: "removeIcon")!, for: .normal)
let clearView = UIView(frame: CGRect(x: 0, y: 0, width: 22, height: 12))
clearView.addSubview(clearButton)
self.rightView = clearView
clearButton.addTarget(self, action: #selector(clearClicked), for: .touchUpInside)
self.clearButtonMode = .never
self.rightViewMode = .whileEditing
}
#objc func clearClicked(sender:UIButton) {
self.text = ""
_ = self.delegate?.textFieldShouldClear?(self)
}
}

Resources