UIbutton of scrollview not interacting - ios

My problem is that my Button and other all controls are not working when i have adding scrollview programmatically to my subView.
override func viewDidLoad() {
super.viewDidLoad()
if(self.appDelegate.screenWidth < 568){
self.scrollView = UIScrollView(frame: view.bounds)
self.scrollView.delegate = self
self.scrollView.contentSize = CGSizeMake(self.appDelegate.screenWidth, 568)
scrollView.delaysContentTouches = false
scrollView.canCancelContentTouches = true
scrollView.scrollEnabled = true
// mainView consists all other controls like UIButton and other
scrollView.addSubview(mainView)
view.addSubview(scrollView)
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if(self.appDelegate.screenWidth < 568){
scrollView.frame = view.bounds
mainView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height)
}
}
Any suggestions for solving this query???
Thanks in advance

I truly believe its the issue with your view hierarchy. You are adding your scroll view on top of all other UI controls UIButton etc. All the UI controls should be sub-view of scroll view for scroll and controls to function well.

Related

IOS Swift4 Not able to scroll a ScrollView

I hv been trying to make a scrollview scroll, just to the extent that the scrollview is supposed to show. However, I am not able to. This is my code.
func setupMainView() {
// This is where the image view and other UIViews which are supposed to go in the contentview are set up
self.setupImagesView()
self.setupView1()
self.setupView2()
self.setupView3()
self.setupView4()
self.scrollView = UIScrollView()
self.scrollView.backgroundColor = UIColor.white
self.view.addSubview(self.scrollView)
self.automaticallyAdjustsScrollViewInsets = false
self.scrollView.contentInset = UIEdgeInsets.zero
self.scrollView.scrollIndicatorInsets = UIEdgeInsets.zero;
self.contentView = UIView()
self.scrollView.layer.masksToBounds = false
self.scrollView.backgroundColor = UIColor.white
self.scrollView.layer.borderWidth = 0
self.scrollView.layer.borderColor = UIColor.white.cgColor
self.view.addSubview(scrollView)
self.contentView.addSubview(imagesScrollView)
self.contentView.addSubview(view1)
self.contentView.addSubview(view2)
self.contentView.addSubview(view3)
self.contentView.addSubview(view4)
self.scrollView.addSubview(contentView)
self.scrollView.contentInset = UIEdgeInsets.zero
self.scrollView.scrollIndicatorInsets = UIEdgeInsets.zero;
var scrollViewHeight:CGFloat = 0.0;
for _ in self.scrollView.subviews {
scrollViewHeight += view.frame.size.height
}
var newHeight = scrollViewHeight * 1.1 + offset + 100
scrollView.contentSize = CGSize(width:screenWidth, height:newHeight)
scrollView.reloadInputViews()
}
The views are getting loaded etc, but I am not manage the scroll. It somehow either too little or too much.
Now, I tried setting the height of contentSize to scrollViewHeight and double of that etc. What I notice is that there is no predictability of how much it will scroll. Change from 1.1 to 1.6 .. there is too much whitescreen below the views, change it to 1.1 or 1.2 it does not even scroll to the bottom.
Note, everything has been set up programmatically, without storyboard etc.
Also note that I need to support all IOS devices with version > 10.
Am a little lost here. What am I doing wrong?
This is a very old way of configuring a scroll view - you should be using auto-layout.
And, you're doing a number of things wrong...
First, we'll assume you are setting frames of the various subviews in code you haven't shown.
However, the code you have shown creates a scrollView and adds it to self.view -- but you never set the frame of the scroll view.
Also, this part of your code:
for _ in self.scrollView.subviews {
scrollViewHeight += view.frame.size.height
}
you've added several views as subviews of contentView, then added contentView as the only subview of scrollView.
And... you are trying to increment scrollViewHeight by the height of your root view instead of the height of the scrollView's subviews.
So, scrollViewHeight will only be the height of self.view.
What you probably want to do is sum the heights of contentView.subviews:
var contentViewHeight: CGFloat = 0
for v in contentView.subviews {
contentViewHeight += v.frame.height
}
contentView.frame.size.height = contentViewHeight
then set the scrollView's contentSize.height to the height of contentView's frame.
Here is a very, very basic example, using explicitly set frame sizes -- again, though, you should start using auto-layout:
class SimpleScrollViewController: UIViewController {
var imagesScrollView: UIView!
var view1: UIView!
var view2: UIView!
var view3: UIView!
var view4: UIView!
var contentView: UIView!
var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
setupMainView()
}
func setupMainView() {
// This is where the image view and other UIViews which are supposed to go in the contentview are set up
self.setupImagesView()
self.setupView1()
self.setupView2()
self.setupView3()
self.setupView4()
self.scrollView = UIScrollView()
// let's use a color other than white so we can see the frame of the scrollView
self.scrollView.backgroundColor = UIColor.cyan
self.view.addSubview(self.scrollView)
self.automaticallyAdjustsScrollViewInsets = false
self.scrollView.contentInset = UIEdgeInsets.zero
self.scrollView.scrollIndicatorInsets = UIEdgeInsets.zero;
self.contentView = UIView()
self.contentView.backgroundColor = UIColor.lightGray
self.scrollView.layer.masksToBounds = false
self.scrollView.layer.borderWidth = 0
self.scrollView.layer.borderColor = UIColor.white.cgColor
self.view.addSubview(scrollView)
self.contentView.addSubview(imagesScrollView)
self.contentView.addSubview(view1)
self.contentView.addSubview(view2)
self.contentView.addSubview(view3)
self.contentView.addSubview(view4)
self.scrollView.addSubview(contentView)
self.scrollView.contentInset = UIEdgeInsets.zero
self.scrollView.scrollIndicatorInsets = UIEdgeInsets.zero;
var contentViewHeight: CGFloat = 0
for v in contentView.subviews {
contentViewHeight += v.frame.height
}
contentView.frame.size.height = contentViewHeight
// don't know what you're doing here....
//scrollView.reloadInputViews()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// here is where you know the frame of self.view
// so, make the scroll view cover the entire view
scrollView.frame = view.frame
// now, make contentView width equal to scrollView width
contentView.frame.size.width = scrollView.frame.size.width
// set the scrollView's content size
scrollView.contentSize = contentView.frame.size
}
func setupImagesView() -> Void {
imagesScrollView = UIView()
imagesScrollView.backgroundColor = .red
imagesScrollView.frame = CGRect(0, 0, 300, 100)
}
func setupView1() -> Void {
view1 = UIView()
view1.backgroundColor = .green
view1.frame = CGRect(20, imagesScrollView.frame.maxY, 300, 200)
}
func setupView2() -> Void {
view2 = UIView()
view2.backgroundColor = .blue
view2.frame = CGRect(40, view1.frame.maxY, 300, 250)
}
func setupView3() -> Void {
view3 = UIView()
view3.backgroundColor = .yellow
view3.frame = CGRect(60, view2.frame.maxY, 200, 275)
}
func setupView4() -> Void {
view4 = UIView()
view4.backgroundColor = .orange
view4.frame = CGRect(80, view3.frame.maxY, 200, 100)
}
}
If I remember correctly you need to in order for scroll view to work you need to implement a couple of delegate methods. You also need a couple of properties set.
contentSize is one
and I think min and max size
see: https://developer.apple.com/documentation/uikit/uiscrollviewdelegate
also see Stanford University's
Paul Hagarty Developing IOS 11 apps with swift episode 9 for loads of information on UIScrollView
https://www.youtube.com/watch?v=B281mrPUGjg
seek to about 31mins for the scroll view information.
This may help in the setup of UIScrollView programatically:
https://sheikhamais.medium.com/how-to-use-the-new-uiscrollview-programmatically-baf270ee9b4

Trying to code a short intro for my app

I'm trying to code a short intros for my first app.
Here is my code:
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
var MainscrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
MainscrollView.delegate = self
//Frames
var singleFrame : CGRect = self.view.frame;
var scrollFrame : CGRect = singleFrame
scrollFrame.size.width *= 3.0 //num. frames
//Views
//ScrollView
MainscrollView = UIScrollView(frame: singleFrame)
view.addSubview(MainscrollView)
MainscrollView.isPagingEnabled = true
MainscrollView.contentSize = scrollFrame.size
//1 frame
let firstView : UIView = UIView(frame: singleFrame)
firstView.backgroundColor = UIColor.red
MainscrollView.addSubview(firstView)
//2 frame
singleFrame.origin.x = firstView.frame.size.width
let secondView : UIView = UIView(frame: singleFrame)
secondView.backgroundColor = UIColor.yellow
MainscrollView.addSubview(secondView)
//3 frame
singleFrame.origin.x = firstView.frame.size.width * 2
let thirdView : UIView = UIView(frame: singleFrame)
thirdView.backgroundColor = UIColor.green
MainscrollView.addSubview(thirdView)
}
func scrollViewDidEndDecelerating(_ MainscrollView : UIScrollView) {
print("in here")
}
}
Unfortunatelly the scrollViewDidEndDecelerating function is never triggered.
I have a couple of needs:
How can I use correctly the scrollViewDidEndDecelerating? (I need it to trigger the event "page changed" for a pageController element).
Can you put me on the right direction to implement some additional graphical effects above the scrollView as objects that enter and exit in the view with a different speed than the scrollView (as Google Calendar Intro, or Evernote Intro, etc.)?
Also, you've created UIScrollView twice:
var MainscrollView = UIScrollView()
and
MainscrollView = UIScrollView(frame: singleFrame)
So, after setting of delegate your MainscrollView created again. You can change your code to set correct frame like that:
MainscrollView.frame = singleFrame
view.addSubview(MainscrollView)
MainscrollView.isPagingEnabled = true
MainscrollView.contentSize = scrollFrame.size
And you must named your property in camel case - mainScrollView

Horizontal Scroll view floating on UIView instead of Paging

I am trying to do a horizontal scroll view similar to a paging type in which I am adding 3 views. I have put the scroll view in my storyboard above a UIView(myView) & have put constraints. Following are my constraints and my code for the same -
ScrollView constraints
My code for the same -
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var contentView: UIView!
override func viewDidLoad()
{
super.viewDidLoad()
scrollView.frame = CGRectMake(0, 0, myView.frame.width, myView.frame.height)
let view1 = UIView(frame: CGRectMake(0, 0, scrollView.frame.width, scrollView.frame.height))
view1.backgroundColor = UIColor.blackColor()
let view2 = UIView(frame: CGRectMake(scrollView.frame.width, 0, scrollView.frame.width, scrollView.frame.height))
view2.backgroundColor = UIColor.redColor()
let view3 = UIView(frame: CGRectMake(scrollView.frame.width*2, 0, scrollView.frame.width, scrollView.frame.height))
view3.backgroundColor = UIColor.whiteColor()
self.scrollView.addSubview(view1)
self.scrollView.addSubview(view2)
self.scrollView.addSubview(view3)
scrollView.contentSize = CGSizeMake(self.scrollView.frame.width*3, scrollView.frame.height)
// Do any additional setup after loading the view.
}
My Problems -
1) The scroll view floats when I run it in a smaller screen.
2)My view1,view2,view3 width is not the same as of that of myView. Since myView is pinged to the view with (0,0,0,0), views "view1,view2,view3" should have the width & height of myView which should have a height equal to (mainView - TopView) & width that of the mainView.
Please help as I am in a damn need of this solution and I am not being able to figure out what to do? Thanks.
You use constraints for MyView so you should probably use constraints for other views. The simplest way to make constraints in runtime using Cartography
https://github.com/robb/Cartography
Don't forget to set height constraint for scrollview in storyboard.
After in your viewDidLoad need to write something like this:
let views = [UIView(), UIView(), UIView()]
views.forEach {
self.scrollView.addSubview($0)
constrain($0) { view1 in
view1.left == view1.superview!.left
view1.right == view1.superview!.right
view1.height == view1.superview!.height
}
}
constrain(views[0], views[1], views[2]) { view1, view2, view3 in
view1.top == view1.superview!.top
view2.top == view1.bottom
view3.top == view2.bottom
view3.bottom == view3.superview!.bottom
}

Use Pan Recognizer to Control ScrollView

I have a scrollView with paging enables. I have a UIView as a subview of the scrollView. When the scrollView reaches the buttom of it's content, I'm turning scrolling off:
scrollView.scrollEnabled = false
because I'm doing other things that require dragging in a part of the scrollView (Yellow part). So the scrollViews offset locks at the buttom of the page. I want to be able to drag in the UIView (red), to enable scrolling of the scrollView, and thereby change the scrollviews content offset.
So I've added a UIPanGestureRecognizer to the UIView, which action enables scrolling of the scrollview.
The problem is that, when I start panning on the UIView, I have to lift the finger and put it down again, before I can drag the scrollView.
Here's some code:
var scrollView: UIScrollView!
var someView: UIView!
var panAGes: UIGestureRecognizer!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
scrollView = UIScrollView(frame: CGRectMake(0, 0, view.frame.width, view.frame.height))
scrollView.contentSize = CGSizeMake(view.frame.width, view.frame.height * 2)
scrollView.pagingEnabled = true
scrollView.delegate = self
someView = UIView(frame: CGRectMake(0, view.frame.height, view.frame.width, 100))
someView.backgroundColor = UIColor.yellowColor()
panAGes = UIPanGestureRecognizer(target: self, action: "panning:")
someView.addGestureRecognizer(panAGes)
scrollView.addSubview(someView)
self.view.addSubview(scrollView)
}
func scrollViewDidScroll(scrollView: UIScrollView) {
// when page is locked
if scrollView.contentOffset.y >= view.frame.height {
scrollView.scrollEnabled = false
}
}
func panning(gesture: UIGestureRecognizer) {
scrollView.scrollEnabled = true
}
How can I make the scrollView scroll, when the panning method is called?
Thank You...

Stick TableHeader Image always on top of the Screen?

I created a sample app here: https://github.com/steffimueller/LTNavigationBar-TestProject
When you pull down the table at the top above the image a white background appears. This should not be the case. The header image should always be bound at the top of the screen. Here is how it looks in my case:
and here is how it should look like:
The former screenshot is from this app using the parallax branch of the git repo. It is the first tab in the parallax demo which has the effect I want.
Here is the code I use to create the table:
class Page1ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var topView:UIView!
var topImageView: UIImageView?
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.setLeftBarButtonItem(UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Cancel, target: self, action: "sdfsdf"), animated: true)
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: cellIndentifier)
self.navigationController?.navigationBar.lt_setBackgroundColor(UIColor.clearColor())
tableView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleWidth
topView = UIView(frame: CGRectMake(0, 0, 320, 212))
topView.contentMode = UIViewContentMode.ScaleToFill
topView.autoresizesSubviews = true
topView.backgroundColor = UIColor.yellowColor()
topView.clipsToBounds = true
tableView.tableHeaderView = topView
let img = UIImage(named: "bg")
topImageView = UIImageView(image: img)
topImageView?.frame = CGRectMake(0, -89, UIScreen.mainScreen().bounds.size.width, 307)
topImageView?.contentMode = UIViewContentMode.ScaleToFill
topView.addSubview(topImageView!)
}
func scrollViewDidScroll(scrollView: UIScrollView) {
let color: UIColor = UIColor(red: 0/255, green: 175/255, blue: 240/255, alpha: 1)
let offsetY:CGFloat = scrollView.contentOffset.y
if offsetY > NAVBAR_CHANGE_POINT {
let alpha:CGFloat = 1 - ((NAVBAR_CHANGE_POINT + 64 - offsetY) / 64)
self.navigationController?.navigationBar.lt_setBackgroundColor(color.colorWithAlphaComponent(alpha))
}
else {
self.navigationController?.navigationBar.lt_setBackgroundColor(color.colorWithAlphaComponent(0))
}
if offsetY < 0 {
let progress:CGFloat = fabs(offsetY) / 300
self.topImageView?.transform = CGAffineTransformMakeScale(1 + progress, 1 + progress)
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
tableView.snp_makeConstraints { (make) -> Void in
make.top.equalTo(self.view).offset(-64)
}
}
}
Edit: I don't want to set tableView.bounces = false.
How can I stick the TableHeader Image always on top of the Screen like in my second screenshot?
There are lots of ways to do this.
Do you want the topView to scroll with the table view? If so, instead of adding the topView as a subview, just assign it to the table view's tableHeaderView property.
Don't want it to scroll? Add the topView to the view controller's view, not the table view. Then position the table view below the top view in the nib/storyboard.
Want the table view to scroll over the image view as the user scrolls down? Put the image view behind the table view, make the table view transparent, and make the table view's contentInset start the first cell below the image.
I'm guessing just messing with the contentInset's top value will get you what you want here.
It's not clear why both the topView and the topImageView are needed. It looks like just the topImageView would be sufficient.
Just add a frame to your tableView like this:
self.tableView.frame=CGRectMake(0, YYY, 320, 307)
where YYY is the Y position you want the table to be positioned at
UPDATE:
Based on your updated question, if you want to have the image appear to be "stuck' to the top of the tableview, even when the user pulls the table down, you need to use the bounds of the tableView to set the frame of your image. Use something like this to set the image frame:
UIImageView *myImage = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f - self.tableView.bounds.size.height, self.view.frame.size.width, 100.0f+self.tableView.bounds.size.height)];
[self.tableView addSubview:myImage];
You need to make sure your image is larger then the visible headerView so it will continue to show as the user pulls the table down.
The "100.0f+" part is just adding height to the image so it will show
into the headerView, adjust this to fit your image and tableView
header.
UPDATE 2
- (void)viewDidLoad {
[super viewDidLoad];
self.myTableView.delegate=self;
self.myTableView.dataSource=self;
UIImageView *myImageView=[[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f - self.myTableView.bounds.size.height, self.view.frame.size.width, 300.0F+self.myTableView.bounds.size.height)];
[myImageView setClipsToBounds:TRUE];
[myImageView setImage:[UIImage imageNamed:#"myImage.jpg"]];
[self.myTableView addSubview:myImageView];
}
You have to use the following in viewDidLoad():
topView = UIView(frame: CGRectMake(0, 0, 320, 300))
let testView = UIView(frame: CGRectMake(0, 0, 320, 200))
testView.backgroundColor = UIColor.clearColor()
tableView.tableHeaderView = testView
let img = UIImage(named: "bg")
topImageView = UIImageView(image: img)
topImageView?.frame = CGRectMake(0, 0, 320, 180)
topView.addSubview(topImageView!)
topImageView?.contentMode = UIViewContentMode.ScaleToFill
tableView.addSubview(topView!)
tableView.sendSubviewToBack(topView!)
Try by adding an ImageView just below the UITableView(background color should be clearColor) and setting the
yourTableView.contentInset = UIEdgeInsetsMake(100.0, 0.0, 0.0, 0.0).
If you want to bound the UIImage to top of the screen then do the following things. Disable Bounce property of UITableView. you can disable that property from xib or programmatically as well. here i write the code for disable Bounce property programmatically in swift.
self.tableView.bounces = false
Hope this help you.
What i did in my case is to use tableHeaderView instead of section header like, myTableView.tableHeaderView = myImageView
and then in scrollViewDidScrollMethod,
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.contentOffset.y < 0
{
scrollView.layoutIfNeeded()
var headerFrame = myTableView.tableHeaderView?.frame
headerFrame?.origin.y = scrollView.contentOffset.y
headerFrame?.size.height = headerHeight-scrollView.contentOffset.y //headerHeight is a constant for actual height of header on storyboard
myTableView.tableHeaderView?.frame = headerFrame!
}
}
Hope this helps in your case

Resources