XCode Swift 2 UITableViewCell dynamic height based on distance to center - ios

Im trying to create a custom date day picker from a TableView where the numbers get larger as they get toward the center of the screen. For example in the following image: Date Picker example
I'm storing the cell heights and calling the following code in scrollViewDidEndDragging, scrollViewDidEndDecelerating, and of course the height changes only take place after the scroll has happened, but how could I dynamically change the cell heights as it moves?
let pathForCenterCell = self.tableView.indexPathForRowAtPoint(CGPointMake(CGRectGetMidX(self.tableView.bounds), CGRectGetMidY(self.tableView.bounds)))
self.cellHeights[pathForCenterCell!.row - 2] = 88
self.cellHeights[pathForCenterCell!.row - 1] = 120
self.cellHeights[pathForCenterCell!.row] = 160
self.cellHeights[pathForCenterCell!.row + 1] = 120
self.cellHeights[pathForCenterCell!.row + 2] = 88
And how should I setup constraints so that the boxes in the cells and numbers grow along with the cell height and maintain the same space between them horizontally (see the above image)

Related

How to set UITextView's height dynamically in UITableViewCell based on string size?

I understand that this question has been asked here, but it didn't solve my problem as the link in the accepted answer is down and the minimal example didn't help.
Here is a picture of my custom UITableViewCell & all its constraints:
Each post contains these UI elements. The only element that could make each cell's height different is messageView, because its height depends on the string being displayed. Question is, how do I dynamically set each cell's height? Here's what I have now (Does NOT work, messageView is not shown at all):
func cellForRowAt(indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(...) as! PostCell
let message = ...
cell.messageView.text = message
return cell
}
func heightForRowAt(indexPath: IndexPath) -> CGFloat {
var cellMinimumHeight: CGFloat = 120
if let cell = tableView.cellForRow(at: indexPath) as? PostCell {
let size = cell.messageView.sizeThatFits(cell.messageView.frame.size)
cellMinimumHeight += size.height
}
return cellMinimumHeight
}
in heightForRowAt function, the if is not being executed, therefore, all cells' heights are cellMinimumHeight = 120.
How could I make each cell's height = 120 + messageView's height?
---------------------------------EDIT 1---------------------------------
Made a mistake in the picture, messageView's height is not set
When using Auto-Layout for dynamically sizing cells, you don't really need to implement sizeThatFits(...). If the constraints are setup correctly, then you only need to disable the scrolling of the UITextView.
From code:
yourTextView.scrollEnabled = false
From IB:
Select your Text View and open Attributes inspector, then
In Attributes Inspector select your UITextView(messageView) and Uncheck "Scrolling Enabled".
And then change your UITextView(messageView)'s content compression resistence priority as follows:
Horizontal = 750
Vertical = 1000
I hope this will help you.
Just disable UITextview scroll...
But here is no use of UITextview, you can use label also.
In HeightForRow tableview delegate method remove that stuff and use
return UITableViewAutomaticDimension
You have used constrain to make cell hight dynamic
form apple documentation
To define the cell’s height, you need an unbroken chain of constraints
and views (with defined heights) to fill the area between the content
view’s top edge and its bottom edge.
So for your case you need
cell's height = 120 + messageView's height?
So start from Profile Image to measure unbroken chain of constraints from Top to Bottom
Profile Image top = 10 + ImageHeight = 60 ----> 70
MessageView top = 10 + set minimum height to message say 20 one line if every cell should have message even if one word and set this height Greater than or equal to 20 make sure that you set Scroll enable = false
so message Height minimum = 10 top + 20 + 10 bottom ---> 40
Menu Stack view Height ---> 30
So all Total = 70 + 40 + 30 = 140 this default hight no cell will be less than this
Also you must set the table view’s rowHeight property to UITableViewAutomaticDimension. You must also assign a value to the estimatedRowHeight property
tableView.estimatedRowHeight = 130.0
tableView.rowHeight = UITableViewAutomaticDimension
Here is apple documentation Here

UICollectionView stick to a cell even if it's content offset may change

This is a hard one, I hope I can explain it properly.
All right, so the thing is that I have a UICollectionView where the height of the cell is dynamically changing using collectionView.collectionViewLayout.invalidateLayout() which guides into the sizeForItemAtIndexPath() method of UICollectionVieFlowLayout.
This works perfectly. There is new content, it resizes, moves the other cells according to it, etc. Now, my collection view's content size is probably pretty big, that means when I'm stopping at cell number, say, 23, and cell number 15 is not even displayed but is changing it's size, it is going to make my cell number 23 move up or down. Can I kind of throw an "anchor" to where I currently am? Here's the code that's resizing the cell, triggered by Firebase:
cell.resizeToText(text: text!)
let size = CGSize(width: self.view.frame.width, height: cell.mainView.frame.height + (cell.mainView.frame.origin.y*2.5))
let invalidationIndex = indexPath.row + 1
self.invalidationSizeDictionary[invalidationIndex] = size
let context = UICollectionViewLayoutInvalidationContext()
context.invalidateItems(at: [indexPath])
self.feedCollectionView.collectionViewLayout.invalidateLayout()
Question: is there a possibility to stay at my current offset position in the collectionView?

How can I change sizes and x/y coords of several UIViews with constraints in one method?

I have two UITableViews.
Once the left one(for first level category) is clicked the right one(for second level) appears.
A UIView with one UILabel and one UIButton appears when the secondary category is clicked. This UIView is shown in the first screenshot. Two-level category is displayed in the UILabel(which says '미디어 > 작가 / 시나리오') and 'X' is a button to delete the category from the array containing it and hide the UIView.
I set the maximum number of categories by 3. The next one shows the second set of category; which is 7 pixels apart from the first UIView. Also, the height of the rounded rectangle view is 19.
If the second one is too long to put in the same line as the first one is in, the background UIView(light blue) should expand its height and make space for the second UIView. To handle this, I got the following codes executed when the second category is added. The margin between the upper and the lower should be 7 pixels too.I didn't add the code going back to single line because even the following one doesn't work as I want.
I want the result to be somewhat like this:
//tableViewBorder: a UIImageView to separate two UITableViews
//index: a UIView to show what level of category each UITableView is for; which says '1차 분야', '2차 분야' in the screenshot
//dffcltyBtnContainer: a UIView on the bottom of the view controller. it is set to be on the bottom by constraints and its height is fixed.
lightBlueView.frame.size.height = 45
index.frame.origin.y = lightBlueView.frame.maxY + 7
catTableView1.frame.origin.y = index.frame.maxY
catTableView2.frame.origin.y = index.frame.maxY
tableViewBorder.frame.origin.y = index.frame.maxY
catTableView1.frame.size.height = dffcltyBtnContainer.frame.minY -
catTableView1.frame.minY - 44
catTableView2.frame.size.height = dffcltyBtnContainer.frame.minY -
catTableView1.frame.minY - 44
tableViewBorder.frame.size.height = dffcltyBtnContainer.frame.minY -
catTableView1.frame.minY - 44
The code work well when it is called in a UIButton action method. The next one shows what the result of the code above works in the button-triggered method. The height of the two UITableViews correctly decreased by the same amount of change of lightBlueView.
If the sum of two rounded rectangles plus 7 is bigger than the width of lightBlueView, the second one is supposed to go down..
However, this one does not work at all in the desired code block, as if it does not exist. 'lightBlueView' has its 19 pixels of height fixed by a constraint and so are its margins with other components with the same level in the UIView(the highest level in the view controller).**
I guess it is because the height of lightBlueView is set but not sure. Setting x and y coordinate of the second category view will be another big challenge thought but that isn't the issue now :(( What does not make the lightBlueView not change its height in the code block below? Or are their some better ways to implement what I want to do? Anything would be a big help to me. Thanks in advance.
//method 'displayResults' shows or hides UIViews for each selected category. I only change '.hidden' values in it.
//selectedResult1~3Text are UILabels.
//selectedCat is an array of struct with two Strings: prim and secn. This one has what categories are chosen.
switch selectedCats.count{
case 1:
///----change width of label----//
selectedResult1Text.text =
selectedCats[0].prim + " > " + selectedCats[0].secn
selectedResult1Text.sizeToFit()
///----change width of label----//
displayResults(true, d: false, t: false)
break
case 2:
///----change width of label----//
selectedResult2Text.text =
selectedCats[1].prim + " > " + selectedCats[1].secn
selectedResult2Text.sizeToFit()
///----change width of label----//
catTableView1.frame.origin.y = index.frame.maxY
catTableView2.frame.origin.y = index.frame.maxY
tableViewBorder.frame.origin.y = index.frame.maxY
catTableView1.frame.size.height = dffcltyBtnContainer.frame.minY -
catTableView1.frame.minY - 44
catTableView2.frame.size.height = dffcltyBtnContainer.frame.minY -
catTableView1.frame.minY - 44
tableViewBorder.frame.size.height = dffcltyBtnContainer.frame.minY -
catTableView1.frame.minY - 44
displayResults(true, d: true, t: false)
break
case 3:
///----change width of label----//
selectedResult3Text.text =
selectedCats[2].prim + " > " + selectedCats[2].secn
selectedResult3Text.sizeToFit()
///----change width of label----//
displayResults(true, d: true, t: true)
break
default:
displayResults(false, d: false, t: false)
break}

iOS: `UICollectionview`, how to get a cell's `contentoffset` by it's `indexPath`

I'm using a UICollectionview with a circular layout. I'm trying to calculate the contentOffsetper item but with the circular layout the full contentsize does not seem match the content.
The collectionview's total contentSize = 780
The content offset of the last item = 397(?)
The content offset per item = 33(?)
Is there any way I can get the offset for an item by it's indexPath or at least the correct (397) value for the last item's in the collectionview? I got these values by testing and printing the contentoffset but I would like to calculate these numbers (33 and 397) by code without having to scroll.
So is there a way to calculate a cell's contentoffset(?) inside the collectionview by it's indexPath?
Thanks!
I found the problem, the contentsize of the scrollview is the size of the content + the size of the uicollectionview's frame. That was the reason the contentSize returned a larger size than the actual content was.
so:
(contentSizeX - collectionviews frame X) / cells = contentOffset per item
(780 - 383) / 12 => 33

Set/Override Padding In UICollectionView Between Cells

I have a UICollectionView and I'm running into an issue with getting the padding between cells. In theory, I should be able to divide the screen by 4, and I can get a cellsize that has 4 images which perfectly take up the screen width. But, it chooses not to do that. Instead it creates 3 images with HUGE padding as shown below:
_cellSize = CGSizeMake(UIScreen.mainScreen().bounds.width/4,UIScreen.mainScreen().bounds.width/4)
So I decreased the cell size a bit to create some padding, and this was closer but I need about half this padding:
_cellSize = CGSizeMake(UIScreen.mainScreen().bounds.width/4.4,UIScreen.mainScreen().bounds.width/4.4)
So I tried making the cells a bit bigger and it rolls over to the next row and puts 3 items with HUGE padding again.
_cellSize = CGSizeMake(UIScreen.mainScreen().bounds.width/4.3,UIScreen.mainScreen().bounds.width/4.3)
Can I specify the padding between cells without it deciding that if the padding is below "x" amount that it creates a new row instead? Like can I set the threshold padding before a new row to say, 0?
I want to make it this thin:
You only need to do the correct calculation that includes the spaces you want to the edges as well as the space between the cells. For instance, if you want 3 cells across with 5 points to the edges and between the cells, you should have something like this,
override func viewDidLoad() {
super.viewDidLoad()
var layout = self.collectionView.collectionViewLayout as UICollectionViewFlowLayout
layout.sectionInset = UIEdgeInsetsMake(0, 5, 0, 5);
layout.minimumInteritemSpacing = 5; // this number could be anything <=5. Need it here because the default is 10.
layout.itemSize = CGSizeMake((self.collectionView.frame.size.width - 20)/3, 100) // 20 is 2*5 for the 2 edges plus 2*5 for the spaces between the cells
}

Resources