# Moving cell images as a table view scrolls

Language: en
Canonical: [Moving cell images as a table view scrolls](<https://allluckly.cn/en/journal/2016-01-28-moving-cell-images-as-a-table-view-scrolls/>)
中文：[中文 HTML](<https://allluckly.cn/%E6%8A%95%E7%A8%BF/tuogao11>)
English: [English HTML](<https://allluckly.cn/en/journal/2016-01-28-moving-cell-images-as-a-table-view-scrolls/>)
Published: 2016-01-28T00:00:00+08:00
Modified: 2026-10-23T10:34:12+08:00
Author: [WzxJiang](<http://www.jianshu.com/users/389c20d5a244/latest_articles>)

Adjusts an image's position using the offset between the cell's centre and its parent view's centre, creating parallax during UITableView scrolling. It records the custom cell and visible-item updates, with adapted code and a link to the original project.

Contributed by WzxJiang and edited and archived by Bison. The article identifies juvham’s kaiyan project as the basis of the adaptation.

[Source listed in the original](<http://www.jianshu.com/users/389c20d5a244/latest_articles>)

English translation of the [Chinese original](<https://allluckly.cn/%E6%8A%95%E7%A8%BF/tuogao11>), translated on 2026-10-23. The article body uses automated translation; app descriptions, historical reading notes and video subtitles receive separate editorial checks. Original publication dates, attribution, code and version notes are retained.

**Before you read** This technical note dates from 2015–2017. The examples have not been rerun as part of this archive update. Read API, dependency and tool details in the context of the original publication date.

Editor: [Bison](<https://allluckly.cn/en/>)  
 Contributor: [WzxJiang](<http://www.jianshu.com/users/389c20d5a244/latest_articles>)

> “Today I saw an excellent effect on CocoaChina by juvham. The author uses many efficient techniques, but provides few comments. I extracted my favorite effect, changed some code, and added comments. I hope you like it. First, here is the effect I extracted:”

![1](<https://allluckly.cn/images/blog/tuogao/tougao11/1.gif>)

## How this effect is implemented

- First, create a UITableView.
- Then create a custom UITableViewCell, for example myCell.h.
- Create several member variables in myCell.h:

```css
/**
*  图片imgView
*/
@property (nonatomic, strong) UIImageView * pictureView;

/**
*  标题label
*/
@property (nonatomic, strong) UILabel * titleLabel;

/**
*  内容Label
*/
@property (nonatomic, strong) UILabel * littleLabel;
```

- Implement them.

```css
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if ([super initWithStyle:style reuseIdentifier:reuseIdentifier]) {


        //取消选中效果
        self.selectionStyle = UITableViewCellSeparatorStyleNone;

        //裁剪看不到的
        self.clipsToBounds = YES;

        //pictureView的Y往上加一半cellHeight 高度为2 * cellHeight，这样上下多出一半的cellHeight
        _pictureView = ({
            UIImageView * picture = [[UIImageView alloc]initWithFrame:CGRectMake(0, -cellHeight/2, kWidth, cellHeight * 2)];

            picture.contentMode = UIViewContentModeScaleAspectFill;

            picture;
        });
        [self.contentView  addSubview:_pictureView];

        _titleLabel = ({
            UILabel * titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, cellHeight / 2 - 30, kWidth, 30)];

            titleLabel.font = [UIFont boldSystemFontOfSize:16];

            titleLabel.textAlignment = NSTextAlignmentCenter;

            titleLabel.textColor = [UIColor whiteColor];

            titleLabel.text = @"标题";

            titleLabel;
        });
        [self.contentView addSubview:_titleLabel];

        _littleLabel = ({
            UILabel * littleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, cellHeight / 2 + 30, kWidth, 30)];

            littleLabel.font = [UIFont systemFontOfSize:14];

            littleLabel.textAlignment = NSTextAlignmentCenter;

            littleLabel.textColor = [UIColor whiteColor];

            littleLabel.text = @"xxxxxxxxxxx";

            littleLabel;

        });
        [self.contentView addSubview:_littleLabel];



    }
    return self;

}
```

- Next, we need a method that supplies an image to the cell's \_pictureView.

```css
- (void)setImg:(UIImage *)img
{
    self.pictureView.image = img;
}
```

- Processing data in willDisplayCell can improve scrolling performance.

```css
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyCell * myCell = (MyCell *)cell;

    [myCell setImg:_dataArray[indexPath.row]];

    [myCell cellOffset];
}
```

\[myCell cellOffset\] is the cell-offset method explained later. Ignore it for now.

- The data is ready. Now let's discuss the important part: scrolling.

```css
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    // visibleCells 获取界面上能显示出来了cell
    NSArray<MyCell *> *array = [self.tableView visibleCells];

    //enumerateObjectsUsingBlock 类似于for，但是比for更快
    [array enumerateObjectsUsingBlock:^(MyCell * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

        [obj cellOffset];

    }]; 
}
```

This method is useful and worth remembering. Someone has tested enumerateObjectsUsingBlock and found it about 4ms faster than for. If you understand it better, please share your thoughts in the comments.

- Now let's discuss cellOffset.

```css
- (CGFloat)cellOffset
{
    /*
    - (CGRect)convertRect:(CGRect)rect toView:(nullable UIView *)view;
    将rect由rect所在视图转换到目标视图view中，返回在目标视图view中的rect
    这里用来获取self在window上的位置
    */
    CGRect toWindow = [self convertRect:self.bounds toView:self.window];

    //获取父视图的中心
    CGPoint windowCenter = self.superview.center;

    //cell在y轴上的位移  CGRectGetMidY之前讲过,获取中心Y值
    CGFloat cellOffsetY = CGRectGetMidY(toWindow) - windowCenter.y;

    //位移比例
    CGFloat offsetDig = 2 * cellOffsetY / self.superview.frame.size.height ;

    //要补偿的位移
    CGFloat offset =  -offsetDig * cellHeight/2;

    //让pictureViewY轴方向位移offset
    CGAffineTransform transY = CGAffineTransformMakeTranslation(0,offset);
    self.pictureView.transform = transY;

    return offset;
}
```

cellOffsetY is the key parameter. It obtains the offset between the cell's center and its parent view's center, then shifts the pictureView on the cell.

That completes the animation.

Code  
 [My code](<https://github.com/Wzxhaha/WZXKaiYanDemo>)(If your fundamentals are still developing, start with my version; its comments are detailed.)  
 [Code by the original author, juvham](<https://github.com/juvham/kaiyan>)(It includes more effects, although the code is somewhat difficult to follow.)

---

Recommended reading: [Integrating LianLian Pay into an iOS app](<https://allluckly.cn/en/journal/2016-01-20-integrating-lianlian-pay-into-an-ios-app/>)

