Change UITableViewCell frame but didn't work - objective-c

UITableViewCell *cell = [tableViewController.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
[cell setFrame:CGRectMake(cell.frame.origin.x, cell.frame.origin.y - 34, cell.frame.size.width, cell.frame.size.height)];
I want to change the frame of table view cell, the code work in some ViewController, but some it doesn't work.
I want to know is there something wrong with it.
thanks a lot.

You cannot have full control on the cell frame, especially on the origin. The table view delegate is asked for a table view cell, but then its position depends on the internal logic of the table view in order to correctly place the cell inside the table view (which is a scroll view subclass). When the displayed portion of the table view is refreshed, the cell position is rearranged and the frame origin is updated.
So while your code is not wrong, it conflicts with some table internal rules you cannot fully control and so the results could unpredictable.
If you want instead to see a visible effect of this change, you can move your frame changer code to another part of the code, e.g. inside the tableView:didSelectRowAtIndexPath:
In such case you can for example touch a cell, call this code and change the cell frame and you will the change immediately. But as soon as you scroll the cell out of the iPhone screen, and then you move back this cell in the screen, you will notice that it will re-appear in its original position.

Related

Drag a cell from 1 table view and drop it onto a cell in a 2nd table view to invoke segue

I'm trying to attain a visual interaction between two tables, inside one controller, by dragging and dropping a cell from one table onto another tables cell. When one dragged cell contacts another cell, a segue will be invoked to another controller.
A more detailed description: There are two standard UITableView's inside a UIViewController both that present data in cells utilizing a custom UITableViewCell class (nothing special in terms of what it does) - each cell presents an icon, name & a price. Both tables are placed side-to-side, rather than one on top of the other.
The point of all of this is to have the user tap a cell to create some kind of view object at the tapped location (something that represents the tapped cell) and drag it to the other table view. The dragged object can only be dropped on another cell. This DOESN'T add the dragged object to the other table; the object can only interact with a cell it was dragged & dropped over to invoke a segue to another controller (to do some stuff with the data of the dragged "cell" and the data of the contacted cell).
I've sat on this problem for a while, trying to figure it out. I've tried using touchesBegan & UIGestureRecognizers, but I can't even create some view object upon cell "touchdown" ('didSelectRowAtIndexPath' is useless since it gets called only when the finger is lifted...which null's the ability to drag). Please point me in the right direction or how to solve this problem.
About that touchDouwn event you mentioned, you can achieve that by doing this:
in -(id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
do
//init the cell "foo"
UIButton * bar = [[UIButton alloc] initWithFrame:CGRectMake(0,0,foo.frame.size.width, foo.frame.size.height);
[bar addTarget:self action:#selector(gotATouchDown:) forControlEvents:UIControlEventTouchDown];
bar.tag = indexpath.row; //use this to know where touchDown happend
[foo addSubview:bar];
now the selector function
-(void)gotATouchDown:(UIButton*)sender{
NSLog(#"I just touched row nr %ld ",sender.tag);
}
Not sure what to do next, once I figure it out I'll complete my answer.

UITableViewCell frame isn't updated upon changes

I have a custom UITableViewCell to implement swiping horizontally with UIAttachmentBehavior and a UIPanGestureRecognizer. Here's the relevant portion, in the UITableViewCell subclass:
- (void)panDidChange:(UIPanGestureRecognizer *)gesture {
CGPoint location = [gesture locationInView:[self tableView]];
location.y = CGRectGetMidY(self.frame);
switch (gesture.state) {
case UIGestureRecognizerStateBegan: {
self.panAttachment = [[UIAttachmentBehavior alloc] initWithItem:self attachedToAnchor:location];
[self.animator addBehavior:self.panAttachment];
break;
}
Then, when UIGestureRecognizerStateChanged, I just set the self.panAttachment.anchorPoint as the location.
Now, this works fine from startup, but as soon as I add a cell to the tableView or delete a cell from the tableView and try to swipe, the cell moves to it's previous position before the tableView change (one cell down if a cell was deleted, one cell up if a cell was added). As far, as I can tell, this is because the cell's frame isn't being updated when it's position in the tableView changes, so location's y coordinate is out of sync. I've tried [self setNeedsDisplay] and all other "Update view" methods I could find, to no avail.
I am creating the animator referenced above like so:
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:[self tableView]];
It looks like the issue is in a couple different places:
Your animator is being initialized with your entire table view as the reference view.
You are then creating the attachment behavior with an anchor of midY in the tableView's coordinate system, meaning your attachment behavior is now anchored to a point in the tableView's reference coordinate system that is wherever the center point of the cell is located. I bet if you tried to scroll your tableView, weird things would also happen.
Depending on what your goal is for your dynamics behavior, you need to modify both your animator's reference frame and attachment's anchor point in order to fully define what physics simulation you are trying to achieve. Based on the above, it looks like you are trying to simply move the entire cell on the pan. I would recommend that you try moving only a specific container view inside your view hierarchy instead since the table view is going to be placing your cells directly using frames.
If you are looking to provide a pan with a snap-back effect on cancel, then this effect might be better implemented using a couple of UIAttachmentBehavior instances. One behavior instance to anchor the view you are wanting to swipe to it's resting position, and one to actually perform the panning and move the view like you are doing above during the pan. You can tweak the interaction between the two interactions by changing the damping and frequency. This question is a good reference for dragging in general using dynamic items.
In summary to fix your current issue:
Define your animator's reference bounds to the cell's coordinate system, preferably using cell.contentView
Have your cell manage the animator directly since the animator should only be concerned with a view in it's coordinate system. Your animator should have no knowledge of the table view's view hierarchy. Add/remove UIDynamicBehavior items from your cell's animator.

Moving table view cells down without moving tableview's origin

I want to be able to move/shift the group of UITableViewCells in the UITableView downward, without scrolling the tableView, and without moving the entire tableview downward. The desired effect is that there is an amount of whitespace above the table view cells after they're placed in the table view, and when the user scrolls down through the table view, the white space is covered by the cells.
Don't forget that a UITableView is a subclass of UIScrollView.
And that UIScrollView have this property.
contentInset
The distance that the content view is inset from the enclosing scroll view.
#property(nonatomic) UIEdgeInsets contentInset
Discussion
Use this property to add to the scrolling area around the content. The unit of size is points. The default value is UIEdgeInsetsZero.
I don't fully understand what you are trying to do, so I just hope that this is what you are looking for.
After Question was Edited
Add an empty cell where you want it to be and adjust it's size when needed.
You will need to make some try about doing it animated (using insert and reloadCell) or using the reloadData option of the tableView to get the visual you want.
You could use a tableView header and adjust its size. After changing its size, call:
[tableView reloadData];
If you want to animate the size change, try calling:
[tableView beginUpdates];
[tableView endUpdates];
After changing the header's size.
EDIT 1:
As opposed to a table view header, you could use a static cell as mentioned in the other answer. To animate the size change, use the steps above. Change the size in:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

The accessoryView of a UITableViewCell disappears after the visible view is changed

I'm experiencing this strange situation. I have a UITableView where, when the user selects a cell, a long (network) process begins. So, I performed this in a background thread and I placed (in the didSelectRowAtIndexPath) a UIActivityIndicatorView as the accessory view. This is what I wrote:
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
UIActivityIndicatorView* activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
cell.accessoryView = activityView;
[activityView startAnimating];
[activityView release];
everything seems to work correctly, except that, if during a loading process (when the indicator is animated), I switch the view using a UITabBar, when I go back to the UITableView, the UIActivityIndicatorView that should still be there has disappeared. Any idea of what I did wrong? Thanks!
I was looking back at this issue, and... after reading the question now, I'm laughing :-)
Answer to my own question is: nothing is wrong with the code, it works very well... but making the UIActivityIndicatorView white... makes it difficult to see it on white background :-D :-D The posted code is correct.
When you go back to the table view after going to another tab, cellForRowAtIndexPath: messages are sent to the table view controller to display the cells of the table but the activity indicator view was set as the accessory view of the cell in the didSelectRowAtIndexPath: method. So, essentially, you changed the cell (i.e., displayed the activity indicator view) when the cell was selected but when you left the view and came back the cellForRowAtIndexPath: method was used to re-display the cell (and, hence, no activity indicator view).
You'll have to keep track of what cells currently have activity indicator views and make sure you set the accessory view of those cells with a UIActivityIndicatorView in the cellForRowAtIndexPath: method. Obviously, if the activity associated with a cell has completed then don't display the activity indicator view for that cell so you'll have to keep track of whether the activities have completed yet or not. There are many ways you can do this so you'll have to decide what works best for your situation.
It's not true that cellForRowAtIndexPath: messages are sent (at least necessarily) when returning to the table view from another tab view so I've "deleted" my answer above.

Position of UITableViewCell

I'm using a tableview to display a list of rows and when selected, I want additional controls to appear right below the cell, probably in another view which I will control.
So far, I've managed to get a reference to the selected cell by running through the visiblecells array in the tableview but the frame property always returns a y-coordinate of 0 no matter what scroll position the table is in.
How do I get the position of the cell relative to the window?
I think the best way to deal with table views is in their own terms. That is, if you want to position something new inside the table, put it in a cell. It sounds like you want to subclass UITableViewCell to make your controls, and go through the whole tableView beginUpdates - insertCells - endUpdates process to animate their appearance.