Open btrzupek opened 8 years ago
Hey, just an update here. This particular HorizontalScrollView is intended to show a single item (screen width) at a time. In the calculateMarginBetweenItems() function, is where things get weird, man.
For the other HorizontalScrollViews on the page where were have 3+ items showing, this margin gets calculated reasonably. For this particular HorizontalScrollView that shows one item at a time, it returns a gigantic margin number (approx 1/3 the screen width) and that seems to be where things fall apart.
So, are we going down a dead end trying to display a single item per swipe in the HorizontalScrollView?
Would you post your code of view setup here?
Here is just my guessing, correct me if I am wrong.
You want to show one item with screen width (no margin) at a time, and scroll to next item when user scroll. In such case, I don't think you really need to use this control. For the reason that it is quite easy to implement yourself instead of setup a lot to achieve your purpose (this control is not for this purpose at all). For all the steps you need, is to add all items(no margin) one by one to a scroll view, and get the functions scrollViewWillEndDragging
and getClosestItemByX
from my control, the first one is to detect where will be the scrolling stop and the second is to get the closest item for the stopping point from first function. They would not exactly what you want, but the idea is almost the same.
If you still decide to use this control, here is the setting:
horizontalScrollView.leftMarginPx = 0
horizontalScrollView.miniAppearPxOfLastItem = 0
horizontalScrollView.uniformItemSize = CGSizeMake(screenWidth, screenHeight)
horizontalScrollView.setItemsMarginOnce()
for _ in 1...5{
let button = UIButton(frame: CGRectZero)
button.backgroundColor = UIColor.blueColor()
horizontalScrollView.addItem(button)
}
And change a little bit
public func calculateMarginBetweenItems() -> CGFloat
{
//calculate how many items listed on current screen except the last half appearance one
var numberOfItemForCurrentWidth = floorf(Float((self.frame.size.width-self.leftMarginPx-self.miniAppearPxOfLastItem)/(self.uniformItemSize.width+self.miniMarginPxBetweenItems)))
numberOfItemForCurrentWidth = numberOfItemForCurrentWidth == 0 ? 1 : numberOfItemForCurrentWidth
//round func is not compatible in 32bit devices but only in 64bit(5s and iPad Air), so I use this stupid way :)
return CGFloat(Int((self.frame.size.width-self.leftMarginPx-self.miniAppearPxOfLastItem)/CGFloat(numberOfItemForCurrentWidth) - self.uniformItemSize.width));
}
Thanks for the reply, I tried what you suggested and still got the same results :(
Here is the code that we are using (albeit almost exactly what you posted). The primary difference is that we are building a UIView with mixed content instead of returning a UIButton as you are in your example code. When I return a UIButton, it performs as expected - however when I return more than 1 UIView, then I get the behavior described above.
let rowHeight = self.tableView(self.tableView, heightForRowAtIndexPath: indexPath)
var itemWidth = rowHeight
var miniMarginPxBetweenItems:CGFloat = 2.0
var miniAppearPxOfLastItem:CGFloat = 30.0
var leftMarginPx:CGFloat = 5.0
if indexPath.section == 0 {
itemWidth = self.view.frame.width //-6.0
miniMarginPxBetweenItems = 0.0
miniAppearPxOfLastItem = 0.0
leftMarginPx = 0.0
}
// set cells content here
let horizontalScrollView:ASHorizontalScrollView = ASHorizontalScrollView(frame:CGRectMake(0, 0, tableView.frame.size.width, rowHeight))
// we only allow a single row
if indexPath.row == 0{
var aView:UIView = horizontalScrollView
horizontalScrollView.backgroundColor = UIColor.blackColor()
horizontalScrollView.layer.borderColor = UIColor.blackColor().CGColor
horizontalScrollView.layer.borderWidth = 2
horizontalScrollView.leftMarginPx = leftMarginPx
//horizontalScrollView.miniMarginPxBetweenItems = miniMarginPxBetweenItems
horizontalScrollView.miniAppearPxOfLastItem = miniAppearPxOfLastItem
horizontalScrollView.uniformItemSize = CGSizeMake(itemWidth, rowHeight)
//this must be called after changing any size or margin property of this class to get accurate margin
horizontalScrollView.setItemsMarginOnce()
// dynamically build the content
let addedContent = self.buildContentForSection(indexPath.section, horizontalScrollView: horizontalScrollView, cell: cell)
// did we add any content?
if !addedContent {
// create the missing content view for the category of items
aView = UIView(frame: CGRectMake(0,0, tableView.frame.size.width, rowHeight))
self.buildContentForEmptySection(indexPath.section, view: aView)
}
// add the subview
cell.contentView.addSubview(aView)
// setup autolayout and constraints
aView.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addConstraint(NSLayoutConstraint(item: aView,
attribute: NSLayoutAttribute.Height,
relatedBy: NSLayoutRelation.Equal, toItem: nil,
attribute: NSLayoutAttribute.NotAnAttribute,
multiplier: 1,
constant: rowHeight))
cell.contentView.addConstraint(NSLayoutConstraint(item: aView,
attribute: NSLayoutAttribute.Width,
relatedBy: NSLayoutRelation.Equal,
toItem: cell.contentView,
attribute: NSLayoutAttribute.Width,
multiplier: 1,
constant: 0))
}
Another update:
So, when i return a (Temporary, not the real view I want to return) UIView with some content it all works as expected. However, when I return the real view, things get crazy.
I began looking at what is going on in the real view, and as I was systematically commenting out code, I discovered that the moment that I setup the view constraints with SnapKit for subviews in that UIView that I return, the contents do not display.
For example, if I have a background UIimageView in the UIView that I add to the HorizontalScrollView and I add dynamic constraints to it with SnapKit, it breaks everything.
backgroundImageView.snp_makeConstraints { (make) in
make.edges.equalTo(contentView.snp_edges)
}
So it seems that adding constraints to the subviews of the view I add to the HorizontalScrollView is the problem. Do you have any thoughts into why this would be an issue?
Again, If I have a single view that I return (with constraints), it all displays properly. More than 1 and things don't go well.
I figured out the issue. So SnapKit was not playing well with the constraints I added at the root level of the view (in the code above). When I removed the following, it all works (beautifully) as expected. Thanks so much for your comments and help, it got me to the right spot and got this working!
// setup autolayout and constraints
aView.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addConstraint(NSLayoutConstraint(item: aView,
attribute: NSLayoutAttribute.Height,
relatedBy: NSLayoutRelation.Equal, toItem: nil,
attribute: NSLayoutAttribute.NotAnAttribute,
multiplier: 1,
constant: rowHeight))
cell.contentView.addConstraint(NSLayoutConstraint(item: aView,
attribute: NSLayoutAttribute.Width,
relatedBy: NSLayoutRelation.Equal,
toItem: cell.contentView,
attribute: NSLayoutAttribute.Width,
multiplier: 1,
constant: 0))
I'm grad to hear that! It is always a good thing to solve the problem by yourself.
Hi @terenceLuffy , I am having an issue where I am trying to create a UIView the containerView that contains an ImageView and UILabel and that take that first UIView and add many like that to the ASHorizontalScroll view, but when I try that it seems like all my subviews disappear and are not showing up(only the first view shows up in the horizontal scroll view. So in this case only the container view shows up(without the image and label) now if instead of the container view I first just start with an image view and add a label as a subview, again the label disappears and I only see the image. I would really like each item in the horizontal view to be more complex than just one view, to achieve what I want kind of like friend suggestions in Instagram(see the attached screenshot) and was hoping your library could help me achieve that. Thanks, Armaan
Here is my exact code:
let cell = tableView.dequeueReusableCell(withIdentifier: "SuggestionCell",
for: indexPath)
let horizontalScrollView:ASHorizontalScrollView = ASHorizontalScrollView(frame:CGRect(x: kMargin, y: 0, width: tableView.frame.size.width - kMargin, height: suggestionHeight))
horizontalScrollView.backgroundColor = ColorHelper.whiteBackgroundColor
horizontalScrollView.uniformItemSize = CGSize(width: kCellWidth, height: kCellHeight!)
//for iPhone 5s and lower versions in portrait
horizontalScrollView.marginSettings_320 = MarginSettings(leftMargin: kMargin , miniMarginBetweenItems: kMargin * 0.5, miniAppearWidthOfLastItem: 0)
// for iPhone 6 plus and 6s plus in portrait
horizontalScrollView.marginSettings_414 = MarginSettings(leftMargin: kMargin , miniMarginBetweenItems: kMargin * 0.5, miniAppearWidthOfLastItem: 0)
// for iPhone 6 plus and 6s plus in landscape
horizontalScrollView.marginSettings_736 = MarginSettings(leftMargin: kMargin , miniMarginBetweenItems: kMargin * 0.5, miniAppearWidthOfLastItem: 0)
//for all other screen sizes that doesn't set here, it would use defaultMarginSettings instead
//this must be called after changing any size or margin property of this class to get acurrate margin
horizontalScrollView.setItemsMarginOnce()
for _ in 1...13{
let singleSuggestionView = UIView(frame: CGRect.zero)
singleSuggestionView.backgroundColor = ColorHelper.blackColor
singleSuggestionView.layer.cornerRadius = 5.0
let imageView = UIImageView(frame: CGRect(x: 0.0, y: 0.0, width: singleSuggestionView.frame.width, height: singleSuggestionView.frame.width * 0.75))
imageView.contentMode = .scaleAspectFill
Utility.setImage(singleSuggestionView, imageURL: "https://projects.liovinci.com/p_54607433ed54a6637989d08d0d2069622b09b35c.jpg", defaultPic: UIImage(named: "placeholder")!)
imageView.clipsToBounds = true
imageView.backgroundColor = ColorHelper.redColor
singleSuggestionView.addSubview(imageView)
horizontalScrollView.addItem(singleSuggestionView)
}
cell.contentView.addSubview(horizontalScrollView)
horizontalScrollView.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addConstraint(NSLayoutConstraint(item: horizontalScrollView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: suggestionHeight))
cell.contentView.addConstraint(NSLayoutConstraint(item: horizontalScrollView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: cell.contentView, attribute: NSLayoutAttribute.width, multiplier: 1, constant: 0))
return cell
Here is the Instagram view:
@armaanbindra I don't think your problem is related to this control. I can see you firstly setup your container frame zero, and then you set the frame of image view with the container's size, that would be 0 totally since the container is not loaded yet, that's why it doesn't show, try to add constraints or design it in storyboard to get your custom view instead, that might be more straight forward to you.
Aha, Oh I see, thanks @terenceLuffy , I was trying to follow your swift example where it set it to CGRect.zero, yet the eventual view that showed up was not zero but the size specified by uniformItemSize, so even though the first value of the frame is CGRect.zero the library uses the uniform size and constraints to reset the first view's frame. I simply changed the height and width of the container frame manually to the fixed height and width of each item that I needed and now it works perfectly, thanks so much for your help and pardon my misunderstanding.
let cell = tableView.dequeueReusableCell(withIdentifier: "SuggestionCell",
for: indexPath)
let horizontalScrollView:ASHorizontalScrollView = ASHorizontalScrollView(frame:CGRect(x: kMargin, y: 0, width: tableView.frame.size.width - kMargin, height: suggestionHeight))
horizontalScrollView.backgroundColor = ColorHelper.whiteBackgroundColor
horizontalScrollView.uniformItemSize = CGSize(width: kCellWidth, height: kCellHeight!)
//for iPhone 5s and lower versions in portrait
horizontalScrollView.marginSettings_320 = MarginSettings(leftMargin: kMargin , miniMarginBetweenItems: kMargin * 0.5, miniAppearWidthOfLastItem: 0)
// for iPhone 6 plus and 6s plus in portrait
horizontalScrollView.marginSettings_414 = MarginSettings(leftMargin: kMargin , miniMarginBetweenItems: kMargin * 0.5, miniAppearWidthOfLastItem: 0)
// for iPhone 6 plus and 6s plus in landscape
horizontalScrollView.marginSettings_736 = MarginSettings(leftMargin: kMargin , miniMarginBetweenItems: kMargin * 0.5, miniAppearWidthOfLastItem: 0)
//for all other screen sizes that doesn't set here, it would use defaultMarginSettings instead
//this must be called after changing any size or margin property of this class to get acurrate margin
horizontalScrollView.setItemsMarginOnce()
for _ in 1...13{
let singleSuggestionView = UIView(frame: CGRect.zero)
singleSuggestionView.backgroundColor = ColorHelper.blackColor
singleSuggestionView.layer.cornerRadius = 5.0
let imageView = UIImageView(frame: CGRect(x: 0.0, y: 0.0, width: kCellWidth, height: kCellHeight * 0.75))
imageView.contentMode = .scaleAspectFill
Utility.setImage(singleSuggestionView, imageURL: "https://projects.liovinci.com/p_54607433ed54a6637989d08d0d2069622b09b35c.jpg", defaultPic: UIImage(named: "placeholder")!)
imageView.clipsToBounds = true
imageView.backgroundColor = ColorHelper.redColor
singleSuggestionView.addSubview(imageView)
horizontalScrollView.addItem(singleSuggestionView)
}
cell.contentView.addSubview(horizontalScrollView)
horizontalScrollView.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addConstraint(NSLayoutConstraint(item: horizontalScrollView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: suggestionHeight))
cell.contentView.addConstraint(NSLayoutConstraint(item: horizontalScrollView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: cell.contentView, attribute: NSLayoutAttribute.width, multiplier: 1, constant: 0))
return cell
@btrzupek Hi, I use SnapKit as well and the result is quite same like you it only shows one view. What are you doing exactly to fix this issue? Are you remove your SnapKit code?
Hey, we love this library!
We are having a bit of difficulty right now though. We have a horizontal scrollview in our view controller. When we add test views, simply UIButtons, to the view they add properly and scroll as expected.
When we wired in our function to show the actual UIView content we desire to be displayed, it gets weird. If we provide only a single view to the horizontal scroll view, all displays as expected. If we provide two or more views, then NO views display at all.
We have stepped through and seen our actual views being created and returned, but the HorizontalScrollView is just not displaying 2 or more.
Any ideas on how we can debug this further?
Thanks!