How to make the entire tableview scroll horizontally in swift - tableview

I have a TableView with one section and many rows.
Each rows contains many uitextfields which are created programmatically, each one are positioning just to the right to the previous one.
This is like a spreadsheet.
I need to have a scroll horizontally the entire TableView.
currently, I have it only for each row independently.
override func viewDidLayoutSubviews() {
let largeur = CGFloat(Double(game!.scores.countColumns()) * cellWidth)
tableView.frame = CGRect(x: tableView.frame.origin.x, y: tableView.frame.origin.y, width: largeur, height: self.view.frame.size.height)
}
What is the code to do this ? and where to put it ?

Related

Why Is Causing This Cocoapod Popover To Come From Tab bar Instead of Button?

I have implemented this Popover Cocoapod by Corin8823,
My Popover code mirrors this code but have a situation to where the origin point of where of the pop over is coming from is my tab bar instead of the button itself.
I have my popover button within a PageViewController linked to a UIView.
I have recreated that set up (minus the Popover Cocoapod) here but you can also see a youtube video approximating that set up here.
I have tried changing the sender to other elements and simply removing it but the results are always the same (popover comes from tab bar). I assume the popover is coming from the parent aka the UIView? instead of the child? I have read in some posts (that I've been unable to relocate) that I should be using something other than sender.frame, but I don't know what to use instead. I also don't see any questions similar enough to this situation that aren't extremely outdated.
The exact Popover code within the button is:
#IBAction func button1Action(_ sender: UIButton) {
//Origin Point
let originPoint = CGPoint(x: sender.frame.midX, y: sender.frame.maxY + 158) //(Y = down)
let popoverView = UIView(frame: CGRect(x: 32, y: sender.bounds.maxY + 20, width: self.view.bounds.width - 64, height: 200))
let textLabel = UILabel(frame: CGRect(x: +15, y: 0, width: popoverView.bounds.width - 15, height: popoverView.bounds.height))
textLabel.lineBreakMode = .byWordWrapping
textLabel.numberOfLines = 0
textLabel.textColor = .white
textLabel.text = "Use neutral framing of the events rather than perceptually colored language. eg:\n\n____ event occured.\n____ person said: '____'.\n____ object was altered in ____ way."
textLabel.textAlignment = .left
popoverView.addSubview(textLabel)
let options: [PopoverOption] = [
.cornerRadius(25),
.color(.systemTeal)
]
let popover = Popover(options: options)
popover.show(popoverView, point: originPoint)
}
I have posted this on the github and it's been about 3 weeks with no response.

NSAttributedString size() method returns incorrect width

I created a custom NSButtonCell subclass which allows customizing padding between a button's contents. In my implementation (the full source code can be found on GitHub) I override titleRect(forBounds:) to position the button title:
var titleSize: NSSize {
return NSSize(width: ceil(attributedTitle.size().width),
height: ceil(attributedTitle.size().height))
}
override func titleRect(forBounds rect: NSRect) -> NSRect {
return CGRect(x: paddingLeft,
y: rect.height / 2 - titleSize.height / 2,
width: titleSize.width,
height: titleSize.height)
}
The result doesn't look good:
To get the desired outcome I have to add an extra padding to the width:
I also tried using boundingRect(with:options:context:) to get the size, but I got the same results.
For future reference: I figured out the issue. When using attributedTitle, it's important to specify the font of the button, so that attributedString.size() can calculate the necessary width correctly. I assumed that by default, calculations are based on the default font for NSButton but apparently that was incorrect. See my commit for more details.

UIPageViewController with Scroll Transition Style automatically adds Safe Area insets for iPhone X

I'm developing image gallery like slider using UIPageViewController and I'm having troubles with UIPageViewController automatic insets in Scroll transition style mode.
Here is my layout:
UIViewController with UIContainerView (magenta background)
UIPageViewController linked to the container (from #1)
List of dynamically created view UIViewController(s) within the page controller (from #2), full width-height views (1. orange, 2. red, 3. green)
It used to work fine for a long time and continue to work with iOS 11 unless it's rendered on iPhone X device with safe area:
I've checked a lot of various options and was able to confirm that it's related specifically to the Scroll mode of the Page Controller. If I switch to PageCurl transition style - it works as expected (full height):
The Page Controller doesn't expose a lot of options to control this behavior for the scroll mode and I wasn't able to "hack" it as well by searching the controls tree and modifying various insets and frame and contentSize related properties. What I can clearly see is that once view controller is created, my scroll view contentSize and frame is 34px smaller then the container frame
> view.frame
{{X=0,Y=0,Width=375,Height=732}}
Bottom: 732
Height: 732
IsEmpty: false
Left: 0
Location: {{X=0, Y=0}}
Right: 375
Size: {{Width=375, Height=732}}
Top: 0
Width: 375
X: 0
Y: 0
> scroll.frame
{{X=-5,Y=0,Width=385,Height=698}}
Bottom: 698
Height: 698
IsEmpty: false
Left: -5
Location: {{X=-5, Y=0}}
Right: 380
Size: {{Width=385, Height=698}}
Top: 0
Width: 385
X: -5
Y: 0
> scroll.contentSize
{{Width=1155, Height=698}}
Height: 698
IsEmpty: false
Width: 1155
I've also set up my autolayout constraints to be linked to superview rather than safe area:
Here is my code for the Home Controller and all the rest is set in a storyboard (alert: C# Xamarin syntax)
private List<UIViewController> viewControllers;
public HomePageViewController (IntPtr handle) : base ( handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var child1 = new UIViewController();
child1.View.BackgroundColor = UIColor.Orange;
var child2 = new UIViewController();
child2.View.BackgroundColor = UIColor.Red;
var child3 = new UIViewController();
child3.View.BackgroundColor = UIColor.Green;
this.viewControllers = new List<UIViewController>
{
child1,
child2,
child3,
};
this.SetViewControllers(new UIViewController[] { child1 }, UIPageViewControllerNavigationDirection.Forward, false, null);
this.GetNextViewController = (c, r) =>
{
var current = this.viewControllers.IndexOf(this.ViewControllers[0]);
if (current >= this.viewControllers.Count - 1)
return null;
return this.viewControllers[current + 1];
};
this.GetPreviousViewController = (c, r) =>
{
var current = this.viewControllers.IndexOf(this.ViewControllers[0]);
if (current <= 0)
return null;
return this.viewControllers[current - 1];
};
}
How can I force my children view controllers to have full height (equals to the frame height of the parent container)?
I think you can solve this issue using code and custom layout. I mean create your UIPageViewController and insert its view to your UIViewController in code not on storyboard. I think you
should override UIViewController.viewDidLayoutSubviews() and set your rects "manually" (at least the one of the UIPageViewController.) Well, when you do it in code, sometimes you even don't need to override UIViewController.viewDidLayoutSubviews() because the template by Apple itself didn't do this. I think because any created view has translatesAutoresizingMaskIntoConstraints = true. So you can also follow this approach.
There is an example when you create a new project and state it is a page based app.
Here is the template if you want (WARNING: This is a part of a template by Apple itself)
var pageViewController: UIPageViewController?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Configure the page view controller and add it as a child view controller.
self.pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
self.pageViewController!.delegate = self
let startingViewController: DataViewController = self.modelController.viewControllerAtIndex(0, storyboard: self.storyboard!)!
let viewControllers = [startingViewController]
self.pageViewController!.setViewControllers(viewControllers, direction: .forward, animated: false, completion: {done in })
self.pageViewController!.dataSource = self.modelController
self.addChildViewController(self.pageViewController!)
self.view.addSubview(self.pageViewController!.view)
// Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
var pageViewRect = self.view.bounds
if UIDevice.current.userInterfaceIdiom == .pad {
pageViewRect = pageViewRect.insetBy(dx: 40.0, dy: 40.0)
}
self.pageViewController!.view.frame = pageViewRect
self.pageViewController!.didMove(toParentViewController: self)
}
You can extend this functionality by extending
I had a similar issue that only happened in the X sizes and after hours of trails and errors I got it fixed.
I am not sure if it's applicable for you or not but the way I have my page view controller VCs is that each VC has an image filling its background. I have 3 pages. Scrolling for the first time looked normal but when I would reverse scroll from page 2 to 1 or from 1 to 0, page 1's image would show around 40 pixels from the side when it should be completely hidden (similar to your screenshots).
So to fix it I had to either set the images to Aspect Fit or clips to bounds = true. I used the latter because it worked better for the UI.
I achieved to have my UIPageViewController display with full screen height with the following code :
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard let contentScrollView = view.subviews.first(where: { $0 is UIScrollView }) else { return }
contentScrollView.frame.size.height = view.frame.height
}

Array of 2 button to add at view

func addStartingButtons2() {
let button = UIButton(frame: CGRect(x: 50, y: buttonY, width: 250, height: 30))
button.layer.cornerRadius = 10 // get some fancy pantsy rounding
button.backgroundColor = UIColor.darkGray
button.setTitle("Button for Villain: \(String(describing: hashes[button]))", for: UIControlState.normal)
buttons.append(button)
buttons.append(button)
for button in buttons {
self.view.addSubview(button)
button.frame.origin.y += 50
}
}
Where:
var hashes = [UIButton : [Double]]()
var buttons = [UIButton]()
Want to add this function 2 same buttons one onder other, but only one button is realised
Well yeah, you are trying to add the same button twice.
I didn't test the code but you should be able to do this by putting the logic in a for loop and adding a bit of padding between the buttons, otherwise you will see them overlapping.
Something like this:
func addStartingButtons2() {
for villain in villains { // this depends on your needs, it's just an example
let button = UIButton(frame: CGRect(x: 50, y: buttonY, width: 250, height: 30))
// Add offset for the next button.
buttonY += 40
button.layer.cornerRadius = 10 // get some fancy pantsy rounding
button.backgroundColor = UIColor.darkGray
button.setTitle("Button for Villain: \(String(describing: hashes[button]))", for: UIControlState.normal)
buttons.append(button)
}
for button in buttons {
self.view.addSubview(button)
button.frame.origin.y += 50
}
// If you want to avoid the second loop
// you can just put view.addSubview(button) inside the first for loop
}
This won't work. Your array buttons is storing a reference of your button, so you are actually putting two references into the array.
To see the result by yourself, put a break point in your loop and you will see the button with same address twice.
If you want to have multiple buttons, you have to create them one by one.

Trying to move UIView off screen and use autolayout

I have a UIView that I would like to animate off the screen and then bring another view into the screen. I'm using auto layout and I have a IBOutlet set up for the left and right NSLayoutConstraint. Its seem that with out a width set for the UIView that the view actually doesn't animate off the screen.
I'm trying to use this code to pus the UIView off:
self.gameViewConstraintLeft.constant = -400
UIView.animateWithDuration(1, animations: { () in
self.view.layoutIfNeeded()
})
self.gameViewConstriantRight.constant = -400
UIView.animateWithDuration(1, animations: { () in
self.view.layoutIfNeeded()
})
I have constraints set up on the top(0), left(0) and right(0). Maybe this is my issue that I'm pinning the view to the edge of the screen, but I want this to work on multiple screen sizes, so I'm just not sure the best method of achieving my goal.
You are going to have problems moving the views if they're pinned on multiple sides horizontally or vertically.
I would suggest the following:
Set up width, height, centerX, and centerY constraints for your two views. The width and height can be set to "Equal Widths" and "Equal Heights" with the superview to allow it to work with multiple screen sizes.
Add an IBOutlets to the centerX constraint. Animate by modifying the constant property of this constraint:
self.gameView1ConstraintCenterX.constant = -400
UIView.animateWithDuration(1) {
self.view.layoutIfNeeded()
}
self.gameView2ConstriantCenterX.constant = 0
UIView.animateWithDuration(1) {
self.view.layoutIfNeeded()
}

Resources