How to update uiview size when orientation is changed? - ios

The view loads with a height of 324 pixels. Then view updates its height to 250 pixels when I turn the device landscape, but after I turn the device from landscape to portrait it doesn't reset the height of the view back to 324 pixels.
import UIKit
class KeyboardViewController: UIInputViewController {
var calcBoard = CalcControl()
var disNum:Double = 0.0
var expandedHeight:CGFloat = 250
override func updateViewConstraints() {
super.updateViewConstraints()
// Add custom view sizing constraints here
}
override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
//self.view.addConstraint(heightconstraints2)
var heightconstraints3:NSLayoutConstraint = NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 0.0, constant: self.expandedHeight)
//self.view.addConstraint(heightconstraints2)
if toInterfaceOrientation == UIInterfaceOrientation.LandscapeLeft{
self.expandedHeight = 250
self.view.addConstraint(heightconstraints3) }
if toInterfaceOrientation == UIInterfaceOrientation.LandscapeRight{
self.expandedHeight = 250
self.view.addConstraint(heightconstraints3)
}
if toInterfaceOrientation == UIInterfaceOrientation.Portrait{
println("In portrait")
println("Transforming")
self.expandedHeight = 324
self.view.addConstraint(heightconstraints3)
}
}
override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
if fromInterfaceOrientation == UIInterfaceOrientation.Portrait{
println("Adjusting...")
self.expandedHeight = 324
}
}
override func viewDidLoad() {
super.viewDidLoad()
println("Loaded")
NSNotificationCenter.defaultCenter().addObserver(self, selector: "LoadNumber:", name: "load", object: nil)
self.deleteBackward()
// Perform custom UI setup here
//self.calcBoard.frame = CGRect(x: 123, y: 0, width: 320, height: 324)
var xibView1 = NSBundle.mainBundle().loadNibNamed("CalcView", owner: nil, options: nil)
self.calcBoard = xibView1[0] as CalcControl
self.view.frame = CGRect(x: 0, y: 0, width: 320, height: 324)
self.view.addSubview(calcBoard)
}
func LoadNumber(notification:NSNotification){
println("got it")
var num = (calcBoard.number as NSNumber).stringValue
println(num)
var proxy = textDocumentProxy as UITextDocumentProxy
proxy.insertText(num)
}
func recieveNumberfromSource()->Double{
return self.disNum
}
func deleteBackward(){
}
func hasText() -> Bool{
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated
}
override func textWillChange(textInput: UITextInput) {
// The app is about to change the document's contents. Perform any preparation here.
}
override func textDidChange(textInput: UITextInput) {
// The app has just changed the document's contents, the document context has been updated.
var textColor: UIColor
var proxy = self.textDocumentProxy as UITextDocumentProxy
if proxy.keyboardAppearance == UIKeyboardAppearance.Dark {
textColor = UIColor.whiteColor()
} else {
textColor = UIColor.blackColor()
}
}
override func viewDidAppear(animated: Bool) {
//self.updateViewConstraints()
var expandedHeight:CGFloat = 324
var heightconstraint:NSLayoutConstraint = NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 0.0, constant: expandedHeight)
self.view.addConstraint(heightconstraint)
}
}

Keep a reference to the heightConstraint when you first add it and update the constant of it when the orientation changes.
override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
if UIInterfaceOrientationIsLandscape(toInterfaceOrientation) {
heightConstraint.constant = 100
} else {
heightConstraint.constant = 300
}
}
An assignment to self.expandedHeight will not change the constraint after its creation.

Related

how could I add a uiactivity indicator in in bottom/footer of collection view?

i am new to swift . i can not figure how can i do it . basically i need to show uiactivity indicator when collection view loaded all data then you try to scrolling then showing uiactivity indicator . it mean load more data from web just wait .
what i did .
///define
var indicatorFooter : UIActivityIndicatorView!
//set up UIActivityIndicatorView to the collection view
override func setupViews() {
indicatorFooter = UIActivityIndicatorView(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(collectionView.frame.width), height: CGFloat(44)))
indicatorFooter.color = UIColor.black
collectionView.addSubview(indicatorFooter)
}
//end of the scroll view then load next 20 data from api
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
// UITableView only moves in one direction, y axis
let currentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height
// Change 10.0 to adjust the distance from bottom
if maximumOffset - currentOffset <= 10.0 {
self.loadMore()
}
}
//request web to down load data
func loadMore(){
//but it is not working indicator
indicatorFooter.startAnimating()
}
Add the following extension to your code:
extension UIView {
// MARK: Activity Indicator
func activityIndicator(show: Bool) {
activityIndicator(show: show, style: .gray)
}
func activityIndicator(show: Bool, style: UIActivityIndicatorViewStyle) {
var spinner: UIActivityIndicatorView? = viewWithTag(NSIntegerMax - 1) as? UIActivityIndicatorView
if spinner != nil {
spinner?.removeFromSuperview()
spinner = nil
}
if spinner == nil && show {
spinner = UIActivityIndicatorView.init(activityIndicatorStyle: style)
spinner?.translatesAutoresizingMaskIntoConstraints = false
spinner?.hidesWhenStopped = true
spinner?.tag = NSIntegerMax - 1
if Thread.isMainThread {
spinner?.startAnimating()
} else {
DispatchQueue.main.async {
spinner?.startAnimating()
}
}
insertSubview((spinner)!, at: 0)
NSLayoutConstraint.init(item: spinner!, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint.init(item: spinner!, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1.0, constant: 0.0).isActive = true
spinner?.isHidden = !show
}
}
}
To add a spinner to your collectionView you would simply call:
collectionView.activityIndicator(show: true)

UIGestureRecognizer not detected on subview

I made a UIView subclass and added a circle view on top right corner of the view. Then I added UIPanGestureRecognizer to the circle view.
The problem is that gesture is only recognized on left bottom part of circle where the circle is located over the super view.
How can I make entire circle to property detected gesture?
Following is entire class code of UIView subclass I made.
import UIKit
class ResizableImageView: UIView {
private let circleWidth: CGFloat = 40
var themeColor: UIColor = UIColor.magentaColor()
lazy var cornerCircle: UIView = {
let v = UIView()
v.layer.cornerRadius = self.circleWidth / 2
v.layer.borderWidth = 1
v.layer.borderColor = self.themeColor.CGColor
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(buttonTouchMoved) )
v.addGestureRecognizer(panGesture)
return v
}()
// Init
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
configureSelf()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupSubviews() {
// Add cornerButton to self and set auto layout
addSubview( cornerCircle )
addConstraintsWithFormat("H:[v0(\(circleWidth))]", views: cornerCircle) // Extension code for setting auto layout
addConstraintsWithFormat("V:[v0(\(circleWidth))]", views: cornerCircle)
addConstraint(NSLayoutConstraint(item: cornerCircle, attribute: .CenterX, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1, constant: 0))
addConstraint(NSLayoutConstraint(item: cornerCircle, attribute: .CenterY, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0))
}
func configureSelf() {
// Set border
layer.borderWidth = 1
layer.borderColor = themeColor.CGColor
}
// Gesture Event
func buttonTouchMoved(gestureRecognizer: UIPanGestureRecognizer) {
let point = gestureRecognizer.locationInView(self)
print(point)
}
}
ViewController
import UIKit
class ImageViewCheckController: UIViewController {
let imageView: ResizableImageView = {
let iv = ResizableImageView()
return iv
}()
override func viewDidLoad() {
super.viewDidLoad()
title = "ImageViewCheck"
view.backgroundColor = UIColor.whiteColor()
setupSubviews()
}
func setupSubviews() {
view.addSubview( imageView )
view.addConstraintsWithFormat("V:|-100-[v0(200)]", views: imageView)
view.addConstraintsWithFormat("H:|-50-[v0(100)]", views: imageView)
}
}
Normally, there is no touch on a subview outside the bounds of its superview.
To change this, you will have to override hitTest(point:withEvent:) on the superview to alter the way hit-testing works:
override func hitTest(point: CGPoint, withEvent e: UIEvent?) -> UIView? {
if let result = super.hitTest(point, withEvent:e) {
return result
}
for sub in self.subviews.reverse() {
let pt = self.convertPoint(point, toView:sub)
if let result = sub.hitTest(pt, withEvent:e) {
return result
}
}
return nil
}

UIInputViewController NSAutoresizingMaskLayoutConstraint issue

I keep trying to implement input accessory VC in my app and I faced with the following issue. When I'm trying to modify the height of the root view of my custom UIInputViewController it's working well despite the one problem. The problem is that in the logs I see the following:
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
<NSAutoresizingMaskLayoutConstraint:0x174490cc0 UIInputView:0x10a80bb80.(null) == 46.5>,
<NSAutoresizingMaskLayoutConstraint:0x17448cd50 UIInputView:0x10a80bb80.height == 76>,
<NSLayoutConstraint:0x17429b710 UIInputView:0x10a80bb80.top == UIInputSetHostView:0x10402e940.top>
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x17429b710 UIInputView:0x10a80bb80.top == UIInputSetHostView:0x10402e940.top>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Code of my custom UIInputViewController:
import UIKit
import RxSwift
import RxCocoa
#objc protocol InputViewControllerDelegate: NSObjectProtocol {
func answerTextViewDidChange(_ textView: UITextView)
}
class InputViewController: UIInputViewController {
fileprivate var closeButton: UIButton?
private var separatorView: UIView?
private var tipLabel: UILabel?
private var answerTextView: ConstrainedTextView?
private var buttonHeightConstraint: NSLayoutConstraint?
private var separatorHeightConstraint: NSLayoutConstraint?
private var answerTextViewBottomConstraint: NSLayoutConstraint?
weak var delegate: InputViewControllerDelegate?
private let junk = DisposeBag()
private var appropriateMaxLines: Int {
let isPortrait = UIDevice.current.orientation.isPortrait
return isPortrait ? 5 : 3
}
var answerText: String {
get {
return answerTextView?.text ?? ""
}
set {
answerTextView?.text = newValue
}
}
var isAnswerTextViewFirstResponder: Bool {
get {
return answerTextView?.isFirstResponder ?? false
}
set {
_ = newValue ? answerTextView?.becomeFirstResponder() : answerTextView?.resignFirstResponder()
}
}
// MARK: - Life Cycle
deinit {
NotificationCenter.default.removeObserver(self)
}
override func loadView() {
super.loadView()
let notifName = Notification.Name.UIDeviceOrientationDidChange
NotificationCenter.default.addObserver(self,
selector: #selector(rotated),
name: notifName,
object: nil)
configureView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
answerTextView?.maxLines = appropriateMaxLines
setCloseButtonDisabledIfNeeded()
}
// MARK: - Layout
private func configureView() {
view.backgroundColor = RGB(0xF6F6F6)
view.frame = CGRect(x: 0, y: 0, width: screenWidth, height: 70)
view.autoresizingMask = [.flexibleWidth]
// Separator
separatorView = UIView()
separatorView?.backgroundColor = UIColor.lightGray
separatorView?.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(separatorView!)
AutoLayoutEqualizeSuper(separatorView, .left, 0)
AutoLayoutEqualizeSuper(separatorView, .right, 0)
AutoLayoutEqualizeSuper(separatorView, .top, 0)
separatorHeightConstraint = AutoLayoutSetAttribute(separatorView, .height, 1)
// Close Button
closeButton = UIButton(type: .system)
closeButton?.setTitle("Hide", for: .normal)
closeButton?.titleLabel?.font = UIFont.systemFont(ofSize: 17)
closeButton?.translatesAutoresizingMaskIntoConstraints = false
closeButton?.addTarget(self, action: #selector(dismissKeyboard), for: .touchUpInside)
view.addSubview(closeButton!)
AutoLayoutSetAttribute(closeButton, .width, 70)
buttonHeightConstraint = AutoLayoutSetAttribute(closeButton, .height, 35)
AutoLayoutEqualizeSuper(closeButton, .right, -5)
view.addConstraint(NSLayoutConstraint(item: closeButton!, attribute: .top, relatedBy: .equal, toItem: separatorView, attribute: .bottom, multiplier: 1, constant: 0))
// Tip Label
tipLabel = UILabel()
tipLabel?.textColor = UIColor.darkGray
tipLabel?.text = "Your answer:"
tipLabel?.font = UIFont.systemFont(ofSize: 17)
tipLabel?.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tipLabel!)
AutoLayoutEqualizeSuper(tipLabel, .left, 5)
AutoLayoutSetAttribute(tipLabel, .height, 35)
view.addConstraint(NSLayoutConstraint(item: tipLabel!, attribute: .right, relatedBy: .equal, toItem: closeButton, attribute: .left, multiplier: 1, constant: 0))
// Text View
answerTextView = ConstrainedTextView()
answerTextView?.backgroundColor = UIColor.white
answerTextView?.delegate = self
answerTextView?.scrollsToTop = false
answerTextView?.showsVerticalScrollIndicator = false
answerTextView?.font = REG_FONT(15)
answerTextView?.translatesAutoresizingMaskIntoConstraints = false
answerTextView?.layer.masksToBounds = true
answerTextView?.layer.cornerRadius = 7
answerTextView?.layer.borderColor = UIColor.lightGray.withAlphaComponent(0.7).cgColor
answerTextView?.layer.borderWidth = 1
view.addSubview(answerTextView!)
AutoLayoutEqualizeSuper(answerTextView, .left, 5)
AutoLayoutEqualizeSuper(answerTextView, .right, -5)
answerTextViewBottomConstraint = AutoLayoutEqualizeSuper(answerTextView, .bottom, -5)
answerTextView?
.rx
.observe(CGRect.self, "bounds")
.distinctUntilChanged {
$0?.height == $1?.height
}
.subscribe(onNext: { [unowned self] newBounds in
if var newHeight = newBounds?.height,
let separatorHeight = self.separatorHeightConstraint?.constant,
let buttonHeight = self.buttonHeightConstraint?.constant,
let bottomSpace = self.answerTextViewBottomConstraint?.constant {
newHeight = newHeight < 35 ? 35 : newHeight
let generalHeight = newHeight + separatorHeight + buttonHeight + abs(bottomSpace)
var frame = self.view.frame
frame.size.height = generalHeight
self.view.frame = frame
}
})
.addDisposableTo(junk)
}
// MARK: - Other methods
fileprivate func setCloseButtonDisabledIfNeeded() {
closeButton?.isEnabled = answerTextView?.isFirstResponder ?? false
}
func rotated() {
answerTextView?.maxLines = appropriateMaxLines
}
}
// MARK: - UITextViewDelegate Protocol Conformance
extension InputViewController: UITextViewDelegate {
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
textView.inputAccessoryView = view
return true
}
func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
textView.inputAccessoryView = nil
return true
}
func textViewDidBeginEditing(_ textView: UITextView) {
setCloseButtonDisabledIfNeeded()
}
func textViewDidEndEditing(_ textView: UITextView) {
setCloseButtonDisabledIfNeeded()
}
func textViewDidChange(_ textView: UITextView) {
delegate?.answerTextViewDidChange(textView)
}
}

Dynamicly insert Views into custom cell with Dynamic Height

Hello Guys i spend few days figuring out how to solve my problem and i am not much skilled in swift i decided ask some profesionals
My Problem:
DATA: array list of events(apointment, task, etc...)
number of events its not always same thats why i have to insert as many views as events in array and height of each cell is always different
custom cell created with xib file
I am inserting views inside cell ( creating column of apointments and tasks) but i have a problem when scrolling everything start to look really bad. Can someone help me and told my why it look like broken lego when scrolling ?
I want to make something like this
I tried add label to left side of my column of views and it did not work. cell height was small and content did not appear because was hidden under next row. Cell height was only height of that one lable. It ignores constrains of last view and only notice constrain of that label
ViewController
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var data = [PLCalendarDay]()
var tableView : UITableView!
let days = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]
override func viewDidLoad() {
super.viewDidLoad()
for (var i = 0; i<5; i++) {
var boleen = true
if i > 2 {boleen = false}
let calendar = NSCalendar.currentCalendar()
let day = calendar.dateByAddingUnit(.Day, value: i, toDate: NSDate(), options: [])
print("robim pole")
self.data.append(PLCalendarDay(day: day!, withEnd: boleen))
}
tableView = UITableView()
tableView.registerNib(UINib(nibName: "PLCalendarCell", bundle: nil), forCellReuseIdentifier: "PLCalendarCellid")
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
tableView.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .None
self.view.addSubview(tableView!)
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(animated: Bool) {
// self.tableView.reloadSections(NSIndexSet(indexesInRange: NSMakeRange(0, self.tableView.numberOfSections)), withRowAnimation: .None)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("davam cell number")
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("davam cell")
let cell = tableView.dequeueReusableCellWithIdentifier("PLCalendarCellid", forIndexPath: indexPath) as! PLCalendarCell
cell.setupCell(data[indexPath.row].events)
//cell.selectionStyle = .None
// cell.day.text = data[indexPath.row].date.dateStringWithFormat("dd")
// let day = data[indexPath.row].date.dateStringWithFormat("dd-MM-yyyy")
// cell.dayWord.text = days[getDayOfWeek(day)!-1]
print("som awake1 1 1 ")
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// cell selected code here
}
func getDayOfWeek(today:String)->Int? {
let formatter = NSDateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
if let todayDate = formatter.dateFromString(today) {
let myCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let myComponents = myCalendar.components(.Weekday, fromDate: todayDate)
let weekDay = myComponents.weekday
return weekDay
} else {
return nil
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 200
}
}
cell file
class PLCalendarCell: UITableViewCell {
#IBOutlet weak var day: UILabel!
#IBOutlet weak var dayWord: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
print("som awake")
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setupCell (events: [PLCalendarEvent]){
let cellWidht = self.contentView.frame.width
var positionY:CGFloat = 10.0
var lastView: UIView? = nil
for event in events {
if event.end != nil {
let view = PLCalendarCellView(frame: CGRectMake(70, positionY, cellWidht, 50.0), time: true)
view.title.text = event.desc
view.time.text = "\(event.start.dateStringWithFormat("dd-MM-yyyy")) - \(event.end!.dateStringWithFormat("dd-MM-yyyy"))"
view.backgroundColor = UIColor.greenColor()
view.layer.cornerRadius = 4
self.addSubview(view)
if lastView == nil {
let constrain = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.TopMargin, multiplier: 1, constant: 10)
self.addConstraint(constrain)
} else {
let constrain = NSLayoutConstraint(item: lastView!, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 10)
self.addConstraint(constrain)
}
lastView = view
positionY += 60.0
}
else {
let view = PLCalendarCellView(frame: CGRectMake(70, positionY, cellWidht, 30.0), time: false)
view.title.text = event.desc
view.backgroundColor = UIColor.greenColor()
view.layer.cornerRadius = 4
self.addSubview(view)
if lastView == nil {
let constrain = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.TopMargin, multiplier: 1, constant: 10)
self.addConstraint(constrain)
} else {
let constrain = NSLayoutConstraint(item: lastView!, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 10)
self.addConstraint(constrain)
}
lastView = view
positionY += 40.0
}
}
// eventHolderView.frame = CGRectMake(0, 0, cellWidht, positionY)
// let constrain = NSLayoutConstraint(item: self.contentView, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: lastView, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10)
// self.addConstraint(constrain)
let constrain = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: lastView, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10)
self.addConstraint(constrain)
}
}
Callendar day
class PLCalendarDay: NSObject {
let date: NSDate!
var events = [PLCalendarEvent]()
init(day: NSDate, withEnd: Bool) {
self.date = NSCalendar.currentCalendar().startOfDayForDate(day)
if withEnd {
for(var i=0; i<5;i++){
events.append(PLCalendarEvent(description: "Only one day", startDate: NSCalendar.currentCalendar().startOfDayForDate(date)))
}
} else {
for(var i=0; i<5;i++){
events.append(PLCalendarEvent(description: "Only one day", startDate: NSCalendar.currentCalendar().startOfDayForDate(date), endDate: date))
}
}
}
}
Callendar event
class PLCalendarEvent : NSObject{
let desc: String
let start: NSDate
var end: NSDate? = nil
init(description: String, startDate: NSDate) {
self.desc = description
self.start = startDate
}
init(description: String, startDate: NSDate, endDate: NSDate) {
self.desc = description
self.start = startDate
self.end = endDate
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
i really cant achieve any good result i will be really thankful for help
I resolve the problem. All i needed was proper constraints but not only vertical but even horizontal.

How to scroll text inside uitextfield iOS

I need to scroll data inside UITextfield so that the text of longer width can be seen by scrolling.
Can someone reply me to solve this?
You can use UITextView: Try below one.
UITextView *textView=[[UITextView alloc] initWithFrame:CGRectMake(20, 40, 200, 70)];
textView.font=[UIFont systemFontOfSize:18.0];
textView.userInteractionEnabled=YES;
textView.backgroundColor=[UIColor whiteColor];
textView.scrollEnabled=YES;
textView.delegate = self;
[self.view addSubview:textView];
I add the textField on a UIScrollView, and change the contentSize when the length of the text changed, and scroll the scrollView when the cursor's position changed or selection range changed.
I have made a demo:
private enum TextRangeChangedType: Int {
case leftAndBack = 0
case leftAndForward
case rightAndBack
case rightAndForward
case none
}
public class ScrollableTextField: UIView {
/// Real textFiled.
///
/// You should set delegate, add actions or resign first responder to this view.
private(set) var textField: UITextField?
// MARK: - Private
private let oneCutWidth: CGFloat = UIScreen.main.bounds.width
private let defaultCutTimes: CGFloat = 3
private var scrollView: UIScrollView?
private weak var tapGesture: UITapGestureRecognizer?
private weak var textFiledWidthConstraint: NSLayoutConstraint?
// MARK: - Private funcs
private func configureSubviews() {
//scroll
scrollView = UIScrollView(frame: .zero)
if let scrollView = scrollView {
scrollView.contentSize = CGSize(width: oneCutWidth * defaultCutTimes, height: 0)
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
scrollView.bounces = false
scrollView.delegate = self
scrollView.backgroundColor = .clear
self.addSubview(scrollView)
// if not using masonry
scrollView.translatesAutoresizingMaskIntoConstraints = false
let scrollLeftConstraint = NSLayoutConstraint(item: scrollView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 0)
let scrollRightConstraint = NSLayoutConstraint(item: scrollView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: 0)
let scrollTopConstraint = NSLayoutConstraint(item: scrollView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
let scrollBottomConstraint = NSLayoutConstraint(item: scrollView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
self.addConstraints([scrollLeftConstraint, scrollRightConstraint, scrollTopConstraint, scrollBottomConstraint])
// scrollView.mas_makeConstraints {[weak self] (make) in // if use masonry
// make?.edges.equalTo()(self)
// }
//text field
textField = InnerTextField(frame: .zero)
let oneCut = oneCutWidth
let times = defaultCutTimes
if let textField = textField as? InnerTextField {
textField.addTarget(self, action: #selector(handleTextField(_:)), for: .editingChanged)
let gesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
gesture.delegate = self
textField.addGestureRecognizer(gesture)
tapGesture = gesture
textField.selectedTextRangeChangedBlock = {[weak self] (type, width) in
guard let scrollView = self?.scrollView else {
return
}
let div: CGFloat = 15
if width < scrollView.contentOffset.x + div {
UIView.animate(withDuration: 0.1, animations: {
scrollView.contentOffset.x = max(width - div, 0)
})
} else if width > scrollView.contentOffset.x + scrollView.bounds.width - div {
UIView.animate(withDuration: 0.1, animations: {
scrollView.contentOffset.x = width - scrollView.bounds.width + div
})
}
}
scrollView.addSubview(textField)
// if not using masonry
textField.translatesAutoresizingMaskIntoConstraints = false
let textLeftConstaint = NSLayoutConstraint(item: textField, attribute: .left, relatedBy: .equal, toItem: scrollView, attribute: .left, multiplier: 1, constant: 0)
let textTopConstrait = NSLayoutConstraint(item: textField, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0)
let textBottomConstrait = NSLayoutConstraint(item: textField, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0)
let textWidthConstrait = NSLayoutConstraint(item: textField, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: oneCut * times)
scrollView.addConstraint(textLeftConstaint)
self.addConstraints([textTopConstrait, textBottomConstrait])
textField.addConstraint(textWidthConstrait)
textFiledWidthConstraint = textWidthConstrait
// textField.mas_makeConstraints {[weak self] (make) in // if use masonry
// make?.left.equalTo()(scrollView)
// make?.top.and()?.bottom()?.equalTo()(self)
// make?.width.equalTo()(oneCut * times)
// }
}
}
}
// MARK: - Life circle
public override init(frame: CGRect) {
super.init(frame: frame)
configureSubviews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Actions
#objc private func handleTap(_ gesture: UITapGestureRecognizer) {
let point = gesture.location(in: textField)
let cloestPosition = textField?.closestPosition(to: point)
if let cloestPosition = cloestPosition {
textField?.selectedTextRange = textField?.textRange(from: cloestPosition, to: cloestPosition)
}
}
#objc private func handleTextField(_ textField: UITextField) {
guard let scrollView = self.scrollView, let hookedTF = textField as? InnerTextField else {
return
}
guard let width = hookedTF.getWidthFromDocumentBeginingToCursor(), let fullWidth = hookedTF.getWidthFromDocumentBeginingToEnd() else {
return
}
let selfWidth = self.bounds.width
if selfWidth == 0 {
return
}
//check max bounds
if scrollView.contentSize.width - fullWidth < oneCutWidth {
if scrollView.contentSize.width <= fullWidth {
scrollView.contentSize.width = fullWidth + oneCutWidth
} else {
scrollView.contentSize.width += oneCutWidth
}
// if not using masonry
textFiledWidthConstraint?.constant = scrollView.contentSize.width
// textField.mas_updateConstraints { (make) in // if use masonry
// make?.width.equalTo()(scrollView.contentSize.width)
// }
self.layoutIfNeeded()
}
if width >= selfWidth - 3 {
if width - scrollView.contentOffset.x >= 0 && width - scrollView.contentOffset.x < selfWidth {
return
}
let diff = max(width - selfWidth + 3, 0)
scrollView.contentOffset.x = diff
} else {
scrollView.contentOffset.x = 0
}
}
}
// MARK: - Delegate
extension ScrollableTextField: UIScrollViewDelegate, UIGestureRecognizerDelegate {
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let currentTextWidth = (textField as? InnerTextField)?.getWidthFromDocumentBeginingToEnd() else {
return
}
let selfFrame = self.frame
if currentTextWidth < selfFrame.width {
scrollView.contentOffset.x = 0
return
}
let maxOffsetX = currentTextWidth - selfFrame.width + 6
if scrollView.contentOffset.x > maxOffsetX {
scrollView.contentOffset.x = maxOffsetX
}
}
public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer == self.tapGesture {
if self.textField?.isFirstResponder ?? false {
return true
} else {
return false
}
}
return super.gestureRecognizerShouldBegin(gestureRecognizer)
}
}
// MARK: - Private class
private class InnerTextField: UITextField {
// MARK: - Public
func getWidthFromDocumentBeginingToCursor() -> CGFloat? {
guard let selectedRange = self.selectedTextRange else {
return nil
}
let width = getWidthFromDocumentBegining(to: selectedRange.start)
return width
}
func getWidthFromDocumentBeginingToEnd() -> CGFloat? {
guard let str = self.text else {
return nil
}
let width = getWidthFrom(string: str)
return width
}
// MARK: - Private
private func changeType(oldRange: UITextRange, newRange: UITextRange) -> TextRangeChangedType {
let oldStart = self.offset(from: beginningOfDocument, to: oldRange.start)
let oldEnd = self.offset(from: beginningOfDocument, to: oldRange.end)
let newStart = self.offset(from: beginningOfDocument, to: newRange.start)
let newEnd = self.offset(from: beginningOfDocument, to: newRange.end)
if (oldStart == newStart) && (oldEnd != newEnd) {
if (newEnd > oldEnd) {
return .rightAndForward
} else if (newEnd < oldEnd) {
return .rightAndBack
}
return .none
}
if (oldStart != newStart) && (oldEnd == newEnd) {
if (newStart < oldStart) {
return .leftAndBack
} else if (newStart > oldStart) {
return .leftAndForward
}
return .none
}
if (oldStart == oldEnd) && (newStart == newEnd) {
if newStart > oldStart {
return .rightAndForward
} else if newStart < oldStart {
return .leftAndBack
}
}
return .none
}
private func getWidthFrom(string text: String) -> CGFloat {
let label = UILabel(frame: .zero)
label.text = text
var defaultFont = UIFont.systemFont(ofSize: 15)
if let font = self.font {
defaultFont = font
}
label.font = defaultFont
label.sizeToFit()
let width = label.bounds.size.width
return width
}
private func getWidthFromDocumentBegining(to position: UITextPosition) -> CGFloat? {
if let textStr = self.text {
let curText = textStr as NSString
let offset = self.offset(from: beginningOfDocument, to: position)
guard offset <= curText.length && offset >= 0 else {
return nil
}
let subStr = curText.substring(to: offset)
let width = getWidthFrom(string: subStr)
return width
}
return nil
}
override var text: String? {
didSet {
self.sendActions(for: .editingChanged)
}
}
override var selectedTextRange: UITextRange? {
willSet {
if let old = selectedTextRange, let `new` = newValue {
let willChangeType = changeType(oldRange: old, newRange: new)
if willChangeType == .leftAndBack || willChangeType == .leftAndForward {
if let width = getWidthFromDocumentBegining(to: new.start) {
selectedTextRangeChangedBlock?(willChangeType, width)
}
} else if willChangeType == .rightAndForward || willChangeType == .rightAndBack {
if let width = getWidthFromDocumentBegining(to: new.end) {
selectedTextRangeChangedBlock?(willChangeType, width)
}
}
}
}
}
var selectedTextRangeChangedBlock: ((_ changType: TextRangeChangedType, _ beforeTextWidth: CGFloat) -> ())?
}
or you can have a preview on my github: https://github.com/sunshuyao/ScrollableTextField
You can do it by this way.
UITextView *textField = [[UITextView alloc]initWithFrame:CGRectMake(100, 100, 60, 50)];
textField.text = #"I need to scroll data inside UITextfield so that the text of longer width can be seen by scrolling.Can someone reply me to solve this.";
textField.delegate = self;
[self.view addSubview:textField];

Resources