QMUI_iOS icon indicating copy to clipboard operation
QMUI_iOS copied to clipboard

使用qmuidemo的ImagePicker的时候,在预览界面左右滑动的时候会出现跳动

Open Ekulelu opened this issue 5 years ago • 2 comments

请填写运行环境

  • [x] 设备:iPhone
  • [x] 系统:iOS 11.3.1
  • [x] Xcode 版本:10.1
  • [x] QMUI iOS 版本:3.1.2

请描述具体问题

使用qmuidemo的ImagePicker的时候,在预览界面左右滑动的时候会出现跳动

相关截图(断点的堆栈、控制台的 log)

IMG_0513.TRIM.MOV.zip

Ekulelu avatar Mar 12 '19 04:03 Ekulelu

这个实际刚好是要渲染后面一张图片,所以可能有点卡顿

zhoon avatar Mar 20 '19 06:03 zhoon

卡顿不止是在渲染图片上,是有其他地方导致的。目前我已经优化了一波,纯图片的时候能做到没那么明显,但是相隔都是视频的时候,第一次还是有轻微的卡顿,这个需要再优化一波,思路是把设置item的操作去重。 下面是我用time profile跑出来的一些结果: 第一个是QMUIZoomImageView里面的创建和销毁video相关的控件(包括注册监听方法)。但这个部分比较奇怪。我用profile去跑QMUI的demo,并没有发现这部分耗时严重,但是我工程确出现了。然后我创了个线程去负责这块的处理。续:这部分现在发现可能是我的model层的代码有问题,取playitem的时候deliveryMode传入了image的枚举变量,然后在获取track的时候有几率会出现特别慢的情况。 第二个是如下图所示,这里置空这些东西产生的消耗也太大了,完全可以只重置上一次设置的内容就行了,不必每次都全部设置为nil。QMUI的demo有出现。简单测试时注释掉之后,明显可以减轻卡顿。 image

第三个地方,图中这里其实使用的是contentView的frame,那么其实用[contentView sizeTofit]就行了。但出现的原因可能是我使用了autolayout布局,QMUI中没测出来这里耗时。 image

=====================分割线========================= 再次补充一波优化: 因为collection的cell预加载机制,在手缓慢滑动到约1/3的时候,如果滑动稍微返回一下会加载显示占大部分的那个cell的返回滑动方向上一个cell。如果再回到最初的滑动方向,又会去加载最初滑动方向的下下个cell。 比如当前我在index为26的cell里面(先假设25和27的cell都已经加载了),往左滑到1/3时候,会去加载28的cell,然后反方向滑动,会去加载25的cell。所以在1/3的位置来回滑动的时候,会拼命地去加载28和25的cell。然后这些都会触发QMUIZoomImageView设置内容的逻辑。里面的[QMUIZoomImageView revertZooming]这个十分地消耗性能,里面有创建消耗逻辑,还有UI的needlayout。 第1点优化:QMUIImagePreviewView给cell增加一个isShowing属性,在willDisplayCell的设置为YES, didEndDisplayingCell设置为NO, 另外在cellForItemAtIndexPath里面,如果走到了[self.delegate imagePreviewView:self renderZoomImageView:zoomView atIndex:indexPath.item]; 那么给zoomview里面的reusedIdentifier赋值上Asset。 然后在前面加上判断。代码如下。这样就可以防止那些没有显示过的cell,多次进行内容设置。

......
if (!cell.isShowing) { //如果这个cell当前没有显示,且之前设置的内容都是一样的,那么不需要重新设置内容。collectionView的调用顺序是先cellforIndex然后才cellWillDisplay。所以showing大部分都是NO的。但有种情况就是在1/3处划来划去的。这种就会去预渲染没有显示的cell的图片内容。而且经常同一个cell加载同一个内容,但都不显示
        QMUIZoomImageView *imageView = zoomImageView ? : [self.imagePreviewView zoomImageViewAtIndex:index];
        if (imageView.reusedIdentifier && imageView.reusedIdentifier == [self.imagesAssetArray objectAtIndex:index]) {
            return cell; //不需要再渲染
        }
    }
    
    // 因为 cell 复用的问题,很可能此时会显示一张错误的图片,因此这里要清空所有图片的显示
    [zoomView cleanContent];
    
    if ([self.delegate respondsToSelector:@selector(imagePreviewView:renderZoomImageView:atIndex:)]) {
         zoomView.reusedIdentifier = [self.imagesAssetArray objectAtIndex:index];
        [self.delegate imagePreviewView:self renderZoomImageView:zoomView atIndex:indexPath.item];
    }
    return cell;

第2点优化:[QMUIZoomImageView revertZooming]调用次数。虽然之前已经优化了一次(在设置内容为nil的时候),但是发现还是有很多的无用调用。留意到代码里面已经在QMUIImagePreviewView 的cellWillDisplay的时候调用了这个方法,但是设置的时候又调用?是不是多余了?我的解决方法:在QMUIZoomImageView也加上isShowing的属性,这个属性的赋值跟随QMUIImagePreviewView的cell的isShowing属性。再加上一个shouldZoom的标记属性。然后把设置内容(setImage,setLivePhoto,setVideoItem)里面的 [self revertZooming]; 都替换为

if (self.isShowing) {
        [self revertZooming];
    } else {
        self.shouldZoom = YES;
    }

然后把QMUIImagePreviewView 的cellWillDisplay的revertZooming改为下面的

- (void)revertZoomingIfNeed {
    if (self.shouldZoom) {
        [self revertZooming]; //记得在revertZooming方法里面添加上self.shouldZoom = NO;
    }
}

这样处理之后,再也不会再1/3处划来划去的时候,多次调用revertZooming了

嗯嗯,总算比较顺滑了。。。

=====================分割线========================= 我居然忽略了一个最重要的优化点!预览图有必要拿原图吗?仅改为屏幕大小的图片之后,QMUI代码明显如丝般顺滑

Ekulelu avatar Mar 20 '19 13:03 Ekulelu