在已过滤的图像之间滑动

我试图让用户在静态图像上的filter之间滑动。 这个想法是,当filter在它上面滚动时,图像保持原位。 Snapchat最近发布了一个实现这个function的版本。 这个video显示了我正在努力完成1:05。

到目前为止,我已经尝试将三个UIImageView放入原始图像的左侧和右侧的scrollview中,并使用scrollView的contentOffset.x调整其框架origin.x和size.width。 我在另一篇文章中发现了这个想法。 将左右内容模式更改为UIViewContentModeLeft和UIViewContentModeRight没有帮助。

接下来,我尝试将所有三个UIImageView堆叠在一起。 我制作了两个CALayer蒙版,并将它们插入到堆栈左侧和右侧的scrollView中,这样当您滚动蒙版时将会展示已过滤的图像。 这不适合我。 任何帮助将不胜感激。

您应该只需要2个图像视图(当前的和传入的,因为这是一个分页样式滚动),并且他们切换每个filter更改后的angular色。 而你的方法使用图层蒙版应该工作,但不是在滚动视图。

所以,确保你的观点组织是这样的:

 UIView // receives all gestures UIScrollView // handles the filter name display, touch disabled UIImageView // incoming in front, but masked out UIImageView // current behind 

每个图像视图都有一个遮罩层,它只是一个简单的图层,您可以修改遮罩层的位置来改变实际可见的图像的多less。

现在,主视图处理平移手势,并使用手势的平移来改变传入图像视图掩模层位置和滚动视图内容偏移量。

随着更改完成,“当前”图像视图不再可见,“传入”图像视图将占用整个屏幕。 “当前”图像视图现在被移动到前面,并成为incoming视图,其面具得到更新,使其透明。 当下一个手势开始时,其图像被更新为下一个filter,并且改变过程重新开始。

随着滚动的发生,您始终可以在后台准备过滤的图像,以便在切换时(快速滚动),图像准备好进入视图。

在我第一次尝试掩盖一个UIImage,而不是一个UIImage视图,但最终得到了一个相当不错的工作解决scheme(它使用UIImageView掩码)下面的错误。 如果您有任何问题,请随时询问。

我基本上创build当前的图像和过滤的图像。 我掩盖UIView(用一个矩形),然后根据滑动调整掩码。

链接到结果: https : //www.youtube.com/watch?v=k75nqVsPggY&list=UUIctdpq1Pzujc0u0ixMSeVw

面具信用: https : //stackoverflow.com/a/11391478/3324388

 @interface FilterTestsViewController () @end @implementation FilterTestsViewController NSArray *_pictureFilters; NSNumber* _pictureFilterIterator; UIImage* _originalImage; UIImage* _currentImage; UIImage* _filterImage; UIImageView* _uiImageViewCurrentImage; UIImageView* _uiImageViewNewlyFilteredImage; CGPoint _startLocation; BOOL _directionAssigned = NO; enum direction {LEFT,RIGHT}; enum direction _direction; BOOL _reassignIncomingImage = YES; - (void)viewDidLoad { [super viewDidLoad]; [self initializeFiltering]; } //set it up for video feed -(void)initializeVideoFeed { } -(void)initializeFiltering { //create filters _pictureFilters = @[@"CISepiaTone",@"CIColorInvert",@"CIColorCube",@"CIFalseColor",@"CIPhotoEffectNoir"]; _pictureFilterIterator = 0; //create initial image and current image _originalImage = [UIImage imageNamed:@"ja.jpg"]; //creates image from file, this will result in a nil CIImage but a valid CGImage; _currentImage = [UIImage imageNamed:@"ja.jpg"]; //create the UIImageViews for the current and filter object _uiImageViewCurrentImage = [[UIImageView alloc] initWithImage:_currentImage]; //creates a UIImageView with the UIImage _uiImageViewNewlyFilteredImage = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)];//need to set its size to full since it doesn't have a filter yet //add UIImageViews to view [self.view addSubview:_uiImageViewCurrentImage]; //adds the UIImageView to view; [self.view addSubview:_uiImageViewNewlyFilteredImage]; //add gesture UIPanGestureRecognizer* pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRecognized:)]; [self.view addGestureRecognizer:pan]; } -(void)swipeRecognized:(UIPanGestureRecognizer *)swipe { CGFloat distance = 0; CGPoint stopLocation; if (swipe.state == UIGestureRecognizerStateBegan) { _directionAssigned = NO; _startLocation = [swipe locationInView:self.view]; }else { stopLocation = [swipe locationInView:self.view]; CGFloat dx = stopLocation.x - _startLocation.x; CGFloat dy = stopLocation.y - _startLocation.y; distance = sqrt(dx*dx + dy*dy); } if(swipe.state == UIGestureRecognizerStateEnded) { if(_direction == LEFT && (([UIScreen mainScreen].bounds.size.width - _startLocation.x) + distance) > [UIScreen mainScreen].bounds.size.width/2) { [self reassignCurrentImage]; }else if(_direction == RIGHT && _startLocation.x + distance > [UIScreen mainScreen].bounds.size.width/2) { [self reassignCurrentImage]; }else { //since no filter applied roll it back if(_direction == LEFT) { _pictureFilterIterator = [NSNumber numberWithInt:[_pictureFilterIterator intValue]-1]; }else { _pictureFilterIterator = [NSNumber numberWithInt:[_pictureFilterIterator intValue]+1]; } } [self clearIncomingImage]; _reassignIncomingImage = YES; return; } CGPoint velocity = [swipe velocityInView:self.view]; if(velocity.x > 0)//right { if(!_directionAssigned) { _directionAssigned = YES; _direction = RIGHT; } if(_reassignIncomingImage && !_filterImage) { _reassignIncomingImage = false; [self reassignIncomingImageLeft:NO]; } } else//left { if(!_directionAssigned) { _directionAssigned = YES; _direction = LEFT; } if(_reassignIncomingImage && !_filterImage) { _reassignIncomingImage = false; [self reassignIncomingImageLeft:YES]; } } if(_direction == LEFT) { if(stopLocation.x > _startLocation.x -5) //adjust to avoid snapping { distance = -distance; } }else { if(stopLocation.x < _startLocation.x +5) //adjust to avoid snapping { distance = -distance; } } [self slideIncomingImageDistance:distance]; } -(void)slideIncomingImageDistance:(float)distance { CGRect incomingImageCrop; if(_direction == LEFT) //start on the right side { incomingImageCrop = CGRectMake(_startLocation.x - distance,0, [UIScreen mainScreen].bounds.size.width - _startLocation.x + distance, [UIScreen mainScreen].bounds.size.height); }else//start on the left side { incomingImageCrop = CGRectMake(0,0, _startLocation.x + distance, [UIScreen mainScreen].bounds.size.height); } [self applyMask:incomingImageCrop]; } -(void)reassignCurrentImage { if(!_filterImage)//if you go fast this is null sometimes { [self reassignIncomingImageLeft:YES]; } _uiImageViewCurrentImage.image = _filterImage; self.view.frame = [[UIScreen mainScreen] bounds]; } //left is forward right is back -(void)reassignIncomingImageLeft:(BOOL)left { if(left == YES) { _pictureFilterIterator = [NSNumber numberWithInt:[_pictureFilterIterator intValue]+1]; }else { _pictureFilterIterator = [NSNumber numberWithInt:[_pictureFilterIterator intValue]-1]; } NSNumber* arrayCount = [NSNumber numberWithInt:(int)_pictureFilters.count]; if([_pictureFilterIterator integerValue]>=[arrayCount integerValue]) { _pictureFilterIterator = 0; } if([_pictureFilterIterator integerValue]< 0) { _pictureFilterIterator = [NSNumber numberWithInt:(int)_pictureFilters.count-1]; } CIImage* ciImage = [CIImage imageWithCGImage:_originalImage.CGImage]; CIFilter* filter = [CIFilter filterWithName:_pictureFilters[[_pictureFilterIterator integerValue]] keysAndValues:kCIInputImageKey,ciImage, nil]; _filterImage = [UIImage imageWithCIImage:[filter outputImage]]; _uiImageViewNewlyFilteredImage.image = _filterImage; CGRect maskRect = CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height); [self applyMask:maskRect]; } //apply mask to filter UIImageView -(void)applyMask:(CGRect)maskRect { // Create a mask layer and the frame to determine what will be visible in the view. CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; // Create a path with the rectangle in it. CGPathRef path = CGPathCreateWithRect(maskRect, NULL); // Set the path to the mask layer. maskLayer.path = path; // Release the path since it's not covered by ARC. CGPathRelease(path); // Set the mask of the view. _uiImageViewNewlyFilteredImage.layer.mask = maskLayer; } -(void)clearIncomingImage { _filterImage = nil; _uiImageViewNewlyFilteredImage.image = nil; //mask current image view fully again [self applyMask:CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end 

部分使用Aggressor的解决scheme,我想出了最简单的方法来设置它,用最less的代码行。

 @IBOutlet weak var topImage: UIImageView! @IBOutlet weak var bottomImage: UIImageView! @IBOutlet weak var scrollview: UIScrollView! override func viewDidLoad() { super.viewDidLoad() scrollview.delegate=self scrollview.contentSize=CGSizeMake(2*self.view.bounds.width, self.view.bounds.height) applyMask(CGRectMake(self.view.bounds.width-scrollview.contentOffset.x, scrollview.contentOffset.y, scrollview.contentSize.width, scrollview.contentSize.height)) } func applyMask(maskRect: CGRect!){ var maskLayer: CAShapeLayer = CAShapeLayer() var path: CGPathRef = CGPathCreateWithRect(maskRect, nil) maskLayer.path=path topImage.layer.mask = maskLayer } func scrollViewDidScroll(scrollView: UIScrollView) { println(scrollView.contentOffset.x) applyMask(CGRectMake(self.view.bounds.width-scrollView.contentOffset.x, scrollView.contentOffset.y, scrollView.contentSize.width, scrollView.contentSize.height)) } 

然后,只需设置图像,并确保您有scrollView上方imageViews。 对于所要求的行为(如snapchat),请确保滚动视图的分页启用设置为true,并确保其背景颜色清晰。 这种方法的好处是你可以免费获得所有的scrollView行为…因为你使用了一个scrollView

您可以使用滚动视图创build可滑动的filter,并带有CIImage的分页滚动。

要么

你可以使用这个: https : //github.com/pauljeannot/SnapSliderFilters