How to embed stack view in scroll view programmatically - ios

I have tried embedding it, but my stack view is dynamic and my app is also changing orientations time to time. I have segment control at the end of the view.
I have also tried googling it but had no luck. thanks in advance.
So far I have done:
In view did load:
mainStackView.axis = UILayoutConstraintAxis.Vertical
mainStackView.spacing = 3
scrollView.frame = self.view.bounds
scrollView.addSubview(mainStackView)
view.addSubview(scrollView)
In view did layout:
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
let top = topLayoutGuide.length
let bottom = bottomLayoutGuide.length
self.mainStackView.frame = CGRect(x: 0, y: top, width: view.frame.width, height: view.frame.height - top - bottom).insetBy(dx: 10, dy: 10)
dispatch_async(dispatch_get_main_queue())
{
self.scrollView.frame = self.view.bounds
self.scrollView.contentSize = CGSize(width: self.view.bounds.width, height: self.segmentedControl.frame.origin.y + self.segmentedControl.frame.height + 50)
}
print(scrollView.contentSize)
}

You need to set the height constraint of segment control.
For Example:
segmentedControl.heightAnchor.constraintEqualToConstant(50).active = true
More over, you can Add Empty bottom view to avoid stack view's must fill mechanism. This will show you desired view output.
var bottomView = UIView(frame: CGRectZero)
stackView.addArrangedSubview(bottomView)

Related

only last added view is visible in UIScrollView iOS

I am facing an issue with scrollView. I have added scrollView in my storyboard as
View
- MainView
- ScrollView
- accountSavingSubView
Now I am trying to add views in accountSavingSubView as below
//MARK:- Create and add wallets on the UI
private func createAndAddWallets()
{
var yPosition : CGFloat = 0.0
//1. Create left hand side wallets with help of keys
for key in dictData.keys
{
let walletView:Wallet = Bundle.main.loadNibNamed("Wallet", owner: self, options: nil)?.first as! Wallet
walletView.translatesAutoresizingMaskIntoConstraints = false
walletView.frame = CGRect(x: 0.0, y: yPosition, width: accountSavingSubView.frame.width, height: accountSavingSubView.frame.height)
walletView.accountNameLabel.text = key
accountSavingSubView.addSubview(walletView)
yPosition += walletView.frame.maxY
walletView.isUserInteractionEnabled = true
print("walletView frame is :\(walletView.frame)")
}
//set continer scroll content size
self.contanerScrollView.contentSize = CGSize(width: self.accountSavingSubView.frame.width, height: CGFloat(80.0/320.0)*UIScreen.main.bounds.width*CGFloat(self.dictData.keys.count))
}
Where dictData is a dictionary of ([String: String]).
But in my view, I can see only last view is added on (x=0, y=0). ScrollView content size is correct & I can scroll without having views except last one at first place(x:0,y:0).
Please let me know what am I doing wrong here in my code while adding views.
You need to comment this
walletView.translatesAutoresizingMaskIntoConstraints = false
as it's used with setting constraints only ,and verify that the supplied frame values here are not 0
walletView.frame = CGRect(x: 0.0, y: yPosition, width: accountSavingSubView.frame.width, height: accountSavingSubView.frame.height)
btw you can also comment it as the frame will be captured as you set it in xib if you make it freedom size

iOS - Display a progress indicator at the center of the screen rather than the view

I want to display a progress indicator at the center of the screen, NOT the view. It should be the center of the view because the view is scrollable. Most answers only tells how to center it in the view. I have this code:
let screenBound = UIScreen.main.bounds
let progressIndc = UIActivityIndicatorView()
progressIndc.frame = CGRect(x: screenBound.width / 2 - 10,
y: screenBound.height / 2 - 10,
width: 20, height: 20)
progressIndc.hidesWhenStopped = true
progressIndc.color = UIColor.gray
progressIndc.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
// self.view is scroll view
self.view.addSubview(progressIndc)
progressIndc.startAnimating()
But it shown near the top in iPhone 7. What should be the right way? I can also do a blocking pop-up dialog with a progress indicator.
if you want to keep the indicator view at the center of screen while scrolling, you can add a overlay view to the current topmost UIWindow, then add your indicator view to the overlay view:
guard let topWindow = UIApplication.shared.windows.last else {return}
let overlayView = UIView(frame: topWindow.bounds)
overlayView.backgroundColor = UIColor.clear
topWindow.addSubview(overlayView)
let hudView = UIActivityIndicatorView()
hudView.bounds = CGRect(x: 0, y: 0, width: 20, height: 20)
overlayView.addSubview(hudView)
hudView.center = overlayView.center
you should do this after the topmost UIViewController's view was attached on the top UIWindow, for example, in viewDidAppearmethod.
you can use center property of UIView
progressIndc.center = self.view.center
for e.g
let screenBound = UIScreen.main.bounds
let progressIndc = UIActivityIndicatorView()
progressIndc.frame = CGRect(x: screenBound.width / 2 - 10,
y: screenBound.height / 2 - 10,
width: 20, height: 20)
progressIndc.hidesWhenStopped = true
progressIndc.color = UIColor.gray
progressIndc.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
// self.view is scroll view
progressIndc.center = self.view.center
self.view.addSubview(progressIndc)
progressIndc.startAnimating()
output
you can try this one to add you indicator on top of the screen. but it's not pretty solution -
AppDelegate.sharedInstance.window?.addSubview(progressIndc);

The bottom content of the scrollView is not not responding to touch events

I have scroll view. In side scroll view I have a container view with trailing,leading,top and bottom constraints and also equal heights. I'm adding views dynamically. I'd updated the content size in
viewWillLayoutSubviews as follows.
override func viewWillLayoutSubviews() {
self.scrollView.contentSize = CGSize(width: self.contentView.frame.width, height: self.contentView.frame.height)
self.contentView.frame = CGRect(x: self.contentView.frame.minX, y: self.contentView.frame.minY, width: self.contentView.frame.width, height: 2500) // code to update the contentView's frame where 2500 is a dummy value
self.contentView.clipsToBounds = true
}
Now I can scroll until my last subview of the container view. But the problem is the last 3 subviews are not responding to the touch events.
I tried the following ways but failed.
also updated the containterView's frame
also updated the scrollview's frame
did not work.
Please help me.
func updateFrame() {
self.scrollView.contentSize = CGSize(width: self.contentView.frame.width, height: self.contentView.frame.height)
self.contentView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.frame = CGRect(x: self.contentView.frame.minX, y: self.contentView.frame.minY, width: self.contentView.frame.width, height: 2500) // code to update the contentView's frame where 2500 is a dummy value
self.contentView.clipsToBounds = true
}
try this.
I am assuming that your scrollview is bigger then Content view

Make UIView fill UIScrollview

I have a paging scrollview with two views, and the first one is to fill the UIScrollview and the second to stay in the middle. I don't know what's going wrong, but it wouldn't fill on iPhone6 but, it fits fine on iPhone5. Below is my code:
View Hierarchy
UIView
--StackView (Properties -- Axis(Vertical) Alignment(Fill) Distribution(Fill) Spacing(0))
--UIView (Fixed height. 60)
--UIView (Main Views Holder)
--ScrollView(Content Size: Screen Width * 2, Height: Height left between it margin to the MainView and BottomView) and I notice, that the scrollview keeps remaining size 433 on both iPhone5 and 6. And when I check my storyboard, that's the exact same height there
--UIView(Height: 102, Width: Screen Width)BottomView
#IBOutlet weak var scrollView: UIScrollView!
var rectanglePhot: UIView!
var squarePhoto: UIView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.contentSize = CGSize(width: self.view.frame.size.width * 2, height: scrollView.frame.size.height)
scrollView.autoresizingMask = .FlexibleWidth
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = UIColor.greenColor()
iniiCameraView()
}
func iniiCameraView() {
rectanglePhot = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.scrollView.frame.size.height)) <-- This is the problematic one
//rectanglePhot = UIView()
let specifyY = self.scrollView.frame.size.height - self.view.frame.size.width
squarePhoto = UIView(frame: CGRect(x: self.view.frame.size.width, y: specifyY, width: self.view.frame.size.width, height: self.view.frame.size.width))
scrollView.addSubview(rectanglePhot)
scrollView.addSubview(squarePhoto)
rectanglePhot.backgroundColor = UIColor.blueColor()
squarePhoto.backgroundColor = UIColor.brownColor()
print("Rect Height ", rectanglePhot.frame.size.height)
print("Scroll Height ", scrollView.frame.size.height)
print("Specify Y ", specifyY)
}
And the image Image Added to Scrollview a index[0]
Add the code in viewdidappear. The autolayout will be applied after viewdidload
Replace
UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.scrollView.frame.size.height))
With :
UIView(frame: CGRect(x: 0, y: 0, width: self.scrollView.bounds.size.width, height: self.scrollView.bounds.size.height))
With this the UIView will take the exact size of you scrollview
if you don't want to use autolayout: add subviews in viewDidLoad, that is fine but you also need to adjust their frames in viewDidLayoutSubviews method of UIViewController since your scrollView will have a different frame after autolayout passes.
if you are ok with using autolayout: don't rely on scrollView for sizing your subviews, relate size of your subviews to the size of self.view

When to use UITouch vs UIScroll

I would like to achieve the design you see in dating apps. Where you can vertically scroll images of a profile and also horizontally scroll to view the next or previous person in the list.
Currently I have my views laid out as such.
Previous-UIView - current UIView - next UIView
UIScrollView. UIScrollView. UIScrollView
Images. Images. Images
UIView. UIView. UIView
Profile info. Profile info. Profile info
UIPageControl. UIPageControl UIPageControl.
Only one of the Views occupies the main view with next and previous off screen. Ideally when the user moves the view left I would programmatically remove the previous view, make current the previous, the next current and add a new view for next. Visa versa for moving right.
What is the best way to scroll the views horizontally?
Should I wrap them all in a UIScrollView? And would that interfere with the UIScrollView sub Views?
Or should I program touch controls to move the views?
Or is there a better way?
I'm still a newbie at iOS development so any help would be greatly appreciated.
So I've tried some experimenting with a test app and I'm pleased to say you can have UIScrollviews inside UIScrollviews.
I was able to get it running perfectly. Here is my code below.
override func viewDidLoad() {
super.viewDidLoad()
self.superView.delegate = self
// Do any additional setup after loading the view, typically from a nib.
var subImages1 = ["IMG_0004.JPG","IMG_0005.JPG","IMG_0008.JPG"]
var subImages2 = ["IMG_0009.JPG","IMG_0010.JPG","IMG_0011.JPG"]
var subImages3 = ["IMG_0013.JPG","IMG_0017.JPG","IMG_0018.JPG"]
self.images.append(subImages1)
self.images.append(subImages2)
self.images.append(subImages3)
self.superView.frame = self.view.frame
self.superView.contentSize = CGSizeMake(self.view.frame.width*3, self.view.frame.height)
self.superView.contentOffset = CGPoint(x:self.view.frame.width,y:0)
self.superView.pagingEnabled = true
self.view.addSubview(self.superView)
//layout the UIVeiws into the master ScrollView
for i in 0...2{
var offset = self.view.frame.width * CGFloat(i)
var pView = UIView()
pView.frame = CGRectMake(offset, 0, self.view.frame.width, self.view.frame.height)
pView.backgroundColor = colours[i]
self.superView.addSubview(pView)
self.profileViews.append(pView)
}
// Add sub Scroll views and images to the Views.
for (index, view) in enumerate(self.profileViews){
var scrollView = UIScrollView()
scrollView.delegate = self
scrollView.frame = CGRectMake(10, 10, self.view.frame.width-20, self.view.frame.height-20)
scrollView.pagingEnabled = true
scrollView.contentSize = CGSizeMake(scrollView.frame.width, scrollView.frame.height * CGFloat(images[index].count))
for (index2, image) in enumerate(images[index]){
var subImage = UIImageView()
subImage.frame = CGRectMake(0, scrollView.frame.height * CGFloat(index2), scrollView.frame.width, scrollView.frame.height)
subImage.contentMode = UIViewContentMode.ScaleAspectFit
subImage.image = UIImage(named: image as! String)
scrollView.addSubview(subImage)
}
view.addSubview(scrollView)
self.scrollViews.append(scrollView)
}
}
//Use the did end decelerating as it executes the code once the scoll has finished moving.
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if(scrollView == self.superView){
var contentOffset = scrollView.contentOffset
var pageWidth = self.superView.frame.width
var fractionalPage:Double = Double(self.superView.contentOffset.x / pageWidth)
var page = lround(fractionalPage)
// In this example I take the last UIView from the stack and move it to the first.
// I would do the same in the real app but update the contents of the view after
if(page == 0){
var tempView = self.profileViews[2]
self.profileViews[2].removeFromSuperview()
self.profileViews.removeAtIndex(2)
for view in self.profileViews{
view.frame = CGRectMake(view.frame.minX + self.view.frame.width, 0, view.frame.width, view.frame.height)
println(view.frame)
}
tempView.frame = CGRectMake(0, 0, tempView.frame.width, tempView.frame.height)
self.profileViews.insert(tempView, atIndex: 0)
self.superView.addSubview(tempView)
var newOffset = contentOffset.x + pageWidth
self.superView.contentOffset = CGPoint(x: newOffset, y: 0)
}
// Take the first view and move it to the last.
if(page == 2){
var tempView = self.profileViews[0]
self.profileViews[0].removeFromSuperview()
self.profileViews.removeAtIndex(0)
for view in self.profileViews{
view.frame = CGRectMake(view.frame.minX - self.view.frame.width, 0, view.frame.width, view.frame.height)
println(view.frame)
}
tempView.frame = CGRectMake(tempView.frame.width*2, 0, tempView.frame.width, tempView.frame.height)
self.profileViews.append(tempView)
self.superView.addSubview(tempView)
var newOffset = contentOffset.x - pageWidth
self.superView.contentOffset = CGPoint(x: newOffset, y: 0)
}
}
}

Resources