How can I build a Matrix of textFields with dynamic cols&rows - ios

At very beginning, I want to just create every textField by my self-design function:
func creatTextField(x x0:Int,y y0: Int,w w0: Int,h h0: Int) -> UITextField{
let x = CGFloat(x0)
let y = CGFloat(y0)
let w = CGFloat(w0)
let h = CGFloat(h0)
let frame = CGRectMake(0, 0, w, h)
let center = CGPointMake(x/2, y/2)
let tf = UITextField(frame: frame)
tf.center = center
view.addSubview(tf)
return tf
}
and In the viewDidLoad(),I just want to add a new TextField:
override func viewDidLoad() {
super.viewDidLoad()
TextField = creatTextField(x: 50, y: 50, w: 100, h: 30)
}
And nothing changed when I ran the program
I am considering that did I miss something such as CONSTRAIN or I should use STACK VIEW to present those textFields correctly?
I hope someone can help me out! :D
b.t.w.
Because it just a test, I just add one textField.But I should be a 2D-Array< UITextField >

Just add this line into your code:
tf.borderStyle = UITextBorderStyle.RoundedRect
And final code will be:
func creatTextField(x x0:Int,y y0: Int,w w0: Int,h h0: Int) -> UITextField{
let x = CGFloat(x0)
let y = CGFloat(y0)
let w = CGFloat(w0)
let h = CGFloat(h0)
let frame = CGRectMake(0, 0, w, h)
let center = CGPointMake(x/2, y/2)
let tf = UITextField(frame: frame)
tf.center = center
tf.borderStyle = UITextBorderStyle.RoundedRect
view.addSubview(tf)
return tf
}

Related

Tether uilabel closely to the text being input to UITextField

I want the currency abbreviation uilabel closely follow text being input into UITextField. What's a good way to
calculate where did the text being input ended so
that
func rightViewRect(forBounds bounds: CGRect) -> CGRect
can calculate the label rect properly?
Among other things I've ended up with this helper:
func rightViewRect(bounds: CGRect,
label: UILabel,
field: UITextField
) -> CGRect
{
let measure = UILabel()
measure.font = field.font
if field.text?.isEmpty ?? true {
measure.text = field.placeholder
} else {
measure.text = field.text
}
let cs = measure.intrinsicContentSize
let lcs = label.intrinsicContentSize
guard lcs.width > 0 else {
return .zero
}
let magicSpace = CGFloat(2)
let unclipped = CGRect(x: cs.width + magicSpace, y: 0, width: lcs.width, height: bounds.height)
let clipped = unclipped.intersection(bounds)
return clipped
}

UICollectionView custom Flow Layout, cells disappearing in landscape

I made a custom flow layout, which works perfectly in portrait but as soon as I go to landscape, the left cell disappears on scroll.
Paging is enabled, the cell reappears if I scroll back 1 px.
My Layout Attributes override
I have tried to use transforms instead of altering frames, results in the same thing.
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var att = super.layoutAttributesForElements(in: rect)!
if !(delegate?.reelPlayerFlowIsPreviewMode() ?? true) {
return att
}
let region = CGRect(x: (self.collectionView?.contentOffset.x)!,
y: (self.collectionView?.contentOffset.y)!,
width: (self.collectionView?.bounds.size.width)!,
height: (self.collectionView?.bounds.size.height)!)
let center = CGPoint(x: region.midX, y: region.midY)
for theCell in att {
print("\(theCell.indexPath.item)\n\(theCell)\n")
let cell = theCell.copy() as! UICollectionViewLayoutAttributes
var f = cell.frame
let cellCenter = CGPoint(x: f.midX, y: f.midY)
let realDistance = min(center.x - cellCenter.x, region.width)
let distance = abs(realDistance)
let d = (region.width - distance) / region.width
let p = (max(d, ReelPlayerFlowLayout.minPercent) * ReelPlayerFlowLayout.maxPercent)
f.origin.x += (realDistance * ((1 - ReelPlayerFlowLayout.maxPercent) + (ReelPlayerFlowLayout.maxPercent - ReelPlayerFlowLayout.minPercent)))
cell.frame = f
cell.size = CGSize (width: f.width * p, height: f.height * p)
let index = att.index(of: theCell)!
att[index] = cell
}
return att
}

UILabel takes long to load swift

I'm trying to create a view of a "match" image and the "match price" label in the top right corner of the match image. So far everything works fine- I create the image in the container view, I create a UIImageView for the background of my price label, but when I create the actual label and customize it, it takes forever to load in my app (that is to say, everything loads- the match image, the price label background image, but not the actual label detailing the price). Can anyone spot where in my code I'm going wrong?
func setupMiniContentScroll(contentScroll: UIScrollView) {
let scalar:Double = 6/19
let contentViewDimension = contentScroll.frame.width * CGFloat(scalar)
let contentScrollWidth = CGFloat(LocalUser.matches.count) * (contentViewDimension + CGFloat(12)) - CGFloat(12)
contentScroll.backgroundColor = UIColorFromHex(0x34495e)
for index in 0..<LocalUser.matches.count {
let match = LocalUser.matches[index]
MatchesManager.globalManager.retrieveMatchThumbnail(match) { img, error in
if let img = img {
//create the mini matches views
let xOrigin = index == 0 ? 12 : CGFloat(index) * contentViewDimension + (CGFloat(12) * CGFloat(index) + CGFloat(12))
let contentFrame = CGRectMake(xOrigin, 10, contentViewDimension, contentViewDimension)
let contentView = self.makeMiniContentView(contentFrame, image: img, matchedPrice: match.matchedPrice)
contentView.match = match
let tap = UITapGestureRecognizer(target: self, action: #selector(BrowseViewController.toggleItemInfo(_:)))
contentView.addGestureRecognizer(tap)
//update the contentScrollView
dispatch_async(dispatch_get_main_queue()) {
contentScroll.addSubview(contentView)
contentScroll.contentSize = CGSizeMake(contentScrollWidth + CGFloat(16), contentScroll.frame.height)
}
}
}
}
}
//functions to create labels and imgViews for MiniMyMatches
func makeMiniContentView(frame: CGRect, image: UIImage, matchedPrice: Int) -> ItemContainer {
let containerView = ItemContainer(frame: frame)
//create the item image
let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: containerView.frame.width, height: containerView.frame.height))
imgView.image = image
imgView.layer.cornerRadius = 5
imgView.layer.masksToBounds = true
imgView.userInteractionEnabled = true
//create the price label
dispatch_async(dispatch_get_main_queue()) {
let priceLabel = self.makeMiniPriceLabel(containerView, matchedPrice: matchedPrice)
containerView.addSubview(imgView)
containerView.addSubview(priceLabel)
}
return containerView
}
func makeMiniPriceLabel(containerView: ItemContainer, matchedPrice: Int) -> UIView {
//price label var
let priceLabelFrame = CGRectMake(containerView.frame.size.width - 35, -7, containerView.frame.size.width * 0.50, containerView.frame.size.height * 0.35)
//create the price container
let priceContainer = UIImageView(frame: priceLabelFrame)
priceContainer.image = UIImage(named: "venn.png")
//create the price label
let priceLabel = UILabel(frame: CGRect(x: 3, y:0, width: priceContainer.frame.width, height: priceContainer.frame.height))
priceLabel.text = "$\(matchedPrice)"
priceLabel.numberOfLines = 1
priceLabel.textColor = UIColor.whiteColor()
priceLabel.font = priceLabel.font.fontWithSize(20)
priceContainer.addSubview(priceLabel)
return priceContainer
}
My guess is that the closure for your retrieveMatchThumbnail function is being called on a background thread. You have code in that closure that is manipulating UI objects. I would move ALL the UI code inside your call to dispatch_async():
MatchesManager.globalManager.retrieveMatchThumbnail(match) { img, error in
if let img = img {
//create the mini matches views
let xOrigin = index == 0 ? 12 : CGFloat(index) * contentViewDimension + (CGFloat(12) * CGFloat(index) + CGFloat(12))
let contentFrame = CGRectMake(xOrigin, 10, contentViewDimension, contentViewDimension)
//update the contentScrollView
dispatch_async(dispatch_get_main_queue()) {
let contentView = self.makeMiniContentView(contentFrame, image: img, matchedPrice: match.matchedPrice)
contentView.match = match
let tap = UITapGestureRecognizer(target: self, action: #selector(BrowseViewController.toggleItemInfo(_:)))
contentView.addGestureRecognizer(tap)
contentScroll.addSubview(contentView)
contentScroll.contentSize = CGSizeMake(contentScrollWidth + CGFloat(16), contentScroll.frame.height)
}
}
}

Return Animation Function

I am wanting to create a function so I can easily implement and make modifications to a loading animation that I am using. I am not sure how to return everything I need to properly and get it to display. Here is the code that I used to create it:
let x = (self.view.frame.size.width / 2)
let y = (self.view.frame.size.height / 2)
self.loadingUI = NVActivityIndicatorView(frame: CGRectMake(x, y, 100, 100))
self.loadingUI.center = CGPointMake(view.frame.size.width / 2,
view.frame.size.height / 2)
self.loadingBackground.backgroundColor = UIColor.lightGrayColor()
self.loadingBackground.frame = CGRectMake(0, 0, 150, 150)
self.loadingBackground.center = (self.navigationController?.view.center)!
self.loadingBackground.layer.cornerRadius = 5
self.loadingBackground.layer.opacity = 0.5
self.navigationController?.view.addSubview(loadingBackground)
self.navigationController?.view.addSubview(loadingUI)
self.loadingUI.type = .BallRotateChase
self.loadingUI.color = UIColor.whiteColor()
self.loadingUI.startAnimation()
Is it possible to write a function that would create that so that I can use it multiple time throughout the app? Most everything is in a navigation controller for this custom app.
Here is an easier and simpler version.. I have added everything in viewDidLoad(), but you can make a new seperate function to take care of this.
I have changed the default loader type to ballClipRotateMultiple and default color to blue. Since the color of the load is also white either change bg color or color of loader.
import NVActivityIndicatorView
class ViewController: UIViewController, NVActivityIndicatorViewable {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let x = self.view.center.x
let y = self.view.center.y
let frame = CGRect(x: (x - 50), y: (y - 50), width: 100, height: 100)
let activityIndicatorView = NVActivityIndicatorView(frame: frame)
activityIndicatorView.type = .ballClipRotateMultiple
activityIndicatorView.color = UIColor.blue
self.view.addSubview(activityIndicatorView)
activityIndicatorView.startAnimating()
}
}
Got it,
func loadingAnimation(loadingUI : NVActivityIndicatorView?, loadingBG : UIView, view : UIView, navController : UINavigationController) -> (NVActivityIndicatorView, UIView) {
var loadUI = loadingUI
var loadBG = loadingBG
let x = (view.frame.size.width / 2)
let y = (view.frame.size.height / 2)
loadUI = NVActivityIndicatorView(frame: CGRectMake(x, y, 100, 100))
loadUI!.center = CGPointMake(view.frame.size.width / 2,
view.frame.size.height / 2)
loadBG.backgroundColor = UIColor.lightGrayColor()
loadBG.frame = CGRectMake(0, 0, 150, 150)
loadBG.center = navController.view.center
loadBG.layer.cornerRadius = 5
loadBG.layer.opacity = 0.5
navController.view.addSubview(loadBG)
navController.view.addSubview(loadUI!)
loadUI!.type = .BallRotateChase
loadUI!.color = UIColor.whiteColor()
loadUI!.startAnimation()
return (loadUI!, loadBG)
}
Did the trick!
install pod
pod 'NVActivityIndicatorView'
then
In App Delegate Class
var window: UIWindow?
var objNVLoader = NVLoader()
class func getDelegate() -> AppDelegate
{
return UIApplication.shared.delegate as! AppDelegate
}
then did finish lunch method add
self.window = UIWindow(frame: UIScreen.main.bounds)
then
func showLoader()
{
self.window?.rootViewController!.addChildViewController(objNVLoader)
self.window?.rootViewController!.view!.addSubview(objNVLoader.view!)
objNVLoader.didMove(toParentViewController: self.window?.rootViewController!)
objNVLoader.view.frame=Constants.kScreenBound
self.window?.isUserInteractionEnabled = false
objNVLoader.showLoader()
}
func dismissLoader(){
objNVLoader.removeFromParentViewController()
objNVLoader.didMove(toParentViewController: nil)
objNVLoader.view.removeFromSuperview()
self.window?.isUserInteractionEnabled = true
objNVLoader.dismissLoader()
}
then
AppDelegate.getDelegate().showLoader()
AppDelegate.getDelegate().dismissLoader()

Layout subviews not working properly

I have troubles with a custom view that Im designing.
Its essentially a table that display 12 labels, where the upper left label and the lower left label has to be width*5 of the other views. I have already added the views and adjusted the frame in layout subviews, but the labels does not appear in the view (already checked with the new views debugger of Xcode
override func layoutSubviews() {
super.layoutSubviews()
let width = self.frame.size.width
let height = self.frame.size.height
let normalWidth = width/10
let normalHeight = height/2
var currentOrigin = CGPoint(x: 0, y: 0)
let nameSize = CGSize(width: normalWidth * 5 - 3, height: normalHeight)
labels[0][0].frame = CGRect(origin: currentOrigin, size: nameSize)
currentOrigin.x += normalWidth
for j in labels[0]{
j.frame = CGRect(origin: currentOrigin, size: CGSize(width: normalWidth - 3, height: normalHeight))
currentOrigin.x += normalWidth
}
currentOrigin.y = normalHeight
currentOrigin.x = 0
labels[1][0].frame = CGRect(origin: currentOrigin, size: nameSize)
for j in labels[1]{
j.frame = CGRect(origin: currentOrigin, size: CGSize(width: normalWidth - 3, height: normalHeight))
currentOrigin.x += normalWidth
}
}
And this is the constructor that Im using. According to the debugger the views are in the superview but they are not visible
init(frame: CGRect) {
labels = Array(count:2, repeatedValue:Array(count:6, repeatedValue: UILabel() ))
super.init(frame: frame)
for i in 0..labels.count{
for j in 0..labels[i].count{
labels[i][j] = UILabel()
labels[i][j].font = currentFont
labels[i][j].adjustsFontSizeToFitWidth = true
labels[i][j].textAlignment = NSTextAlignment.Center
labels[i][j].text = "HOLA MUNDO"
addSubview(labels[i][j])
}
}
for i in 0..labels.count{
if let k = delegate?{
labels[i][0].text = k.name(i+1)
}
}
for i in 0..labels.count{
for j in 1..labels[i].count{
labels[i][j].text = "0"
}
}
}
In case someone has some similar troubles here is the solution that I finally found
labels = Array(count:2, repeatedValue:Array(count:6, repeatedValue: UILabel() ))
This line generates 2 arrays of UILabels, but all items of the arrays point to the same instance of UILabel. also:
labels[0] === labels[1] //They will point to the same instance
The other mistake was iterating in
for i in 0..labels.count{
if let k = delegate?{
labels[i][0].text = k.name(i+1)
}
}
The correct thing was to iterate from 1 to labels.count as the first label had to have a different size.
The correct form to instanciate the arrays is the following:
for i in 0..2{
labels.append([UILabel]())
for j in 0..6{
labels[i].append(UILabel())
labels[i][j].font = currentFont
labels[i][j].adjustsFontSizeToFitWidth = true
labels[i][j].textAlignment = NSTextAlignment.Center
labels[i][j].text = "HOLA MUNDO"
addSubview(labels[i][j])
}
Hope it help you to avoid this bug. It was really hard to find.

Resources