Ios 在过滤后的图像之间滑动

Ios 在过滤后的图像之间滑动,ios,objective-c,calayer,imagefilter,snapchat,Ios,Objective C,Calayer,Imagefilter,Snapchat,我试图允许用户在静态图像的过滤器之间滑动。这个想法是当过滤器在图像上方滚动时,图像保持在原位。Snapchat最近发布了一个实现此功能的版本 到目前为止,我已经尝试将三个UIImageView放到一个scrollview中,分别位于原始图像的左侧和右侧,并使用scrollview的contentOffset.x调整它们的frames origin.x和size.width。我在另一篇文章中发现了这个想法。将左侧和右侧的内容模式更改为UIViewContentModeLeft和UIViewCont

我试图允许用户在静态图像的过滤器之间滑动。这个想法是当过滤器在图像上方滚动时,图像保持在原位。Snapchat最近发布了一个实现此功能的版本

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


接下来,我尝试将所有三个UIImageView堆叠在一起。我制作了两个CALayer遮罩,并将它们插入堆栈左侧和右侧的scrollView中,这样当您滚动遮罩时,将显示过滤后的图像。这对我不起作用。任何帮助都将不胜感激

您应该只需要2个图像视图(当前视图和传入视图,因为这是分页样式的滚动),并且它们在每次过滤器更改后切换角色。使用图层遮罩的方法应该有效,但在滚动视图上不行

因此,请确保您对组织的看法如下:

UIView // receives all gestures
    UIScrollView // handles the filter name display, touch disabled
    UIImageView // incoming in front, but masked out
    UIImageView // current behind
每个图像视图都有一个遮罩层,它只是一个简单的层,您可以修改遮罩层的位置以更改图像的实际可见程度

现在,主视图处理平移手势,并使用手势的平移来更改传入的图像视图遮罩层位置和滚动视图内容偏移

更改完成后,“当前”图像视图将无法再看到,“传入”图像视图将占据整个屏幕。“当前”图像视图现在移到前面,并成为
传入的
视图,其遮罩将更新以使其透明。当下一个手势开始时,其图像将更新到下一个过滤器,更改过程将重新开始


滚动时,您可以随时在后台准备过滤后的图像,以便在切换(快速滚动)时将图像推入视图。

在我的第一次尝试中,尝试屏蔽UIImage而不是UIImage视图时出错,但最终得到了一个相当不错的解决方案(使用UIImageView遮罩)。如果您有问题,请随时提问

我基本上创建了当前图像和过滤后的图像。我屏蔽了UIView(一个矩形),然后根据滑动调整屏蔽

结果链接:

假面信用:

@接口过滤器测试IEWController()
@结束
@实现筛选器测试IEWController
NSArray*_图像过滤器;
NSNumber*\u图片过滤器迭代器;
UIImage*_原始图像;
UIImage*_currentImage;
UIImage*\u过滤器图像;
UIImageView*uiImageViewCurrentImage;
UIImageView*uiImageViewNewlyFilteredImage;
CGPoint\u定位;
BOOL\u directionAssigned=否;
枚举方向{左,右};
枚举方向_方向;
BOOL\u reassignncomingimage=YES;
-(无效)viewDidLoad
{
[超级视图下载];
[自初始化过滤];
}
//将其设置为视频源
-(无效)初始化视频源
{
}
-(无效)初始化筛选
{
//创建过滤器
_pictureFilters=@[@“CicePiatone”、@“CIColorInvert”、@“CicolorCircube”、@“CIFalseColor”、@“Ciphotoeffectinoir”];
_pictureFilterIterator=0;
//创建初始图像和当前图像
_originalImage=[UIImage ImageName:@“ja.jpg”];//从文件创建图像,这将导致一个无效的CIImage,但却是一个有效的CGImage;
_currentImage=[UIImage ImageName:@“ja.jpg”];
//为当前和筛选对象创建UIImageView
_uiImageViewCurrentImage=[[UIImageView alloc]initWithImage:\u currentImage];//使用UIImage创建UIImageView
_uiImageViewNewlyFilteredImage=[[UIImageView alloc]initWithFrame:CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)];//需要将其大小设置为完全,因为它还没有过滤器
//将UIImageView添加到视图
[self.view addSubview:_uiImageViewCurrentImage];//将UIImageView添加到视图中;
[self.view addSubview:_uiImageViewNewlyFilteredImage];
//添加手势
UIPanGestureRecognizer*pan=[[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(SwipereRecognized:)];
[self.view addgestureRecognitor:pan];
}
-(无效)刷卡已识别:(UIPangestureRecognitizer*)刷卡
{
CGFloat距离=0;
CG点停止位置;
如果(swipe.state==UIgestureRecognitizerStateStateStart)
{
_directionAssigned=否;
_startLocation=[swipe locationInView:self.view];
}否则
{
stopLocation=[滑动位置查看:self.view];
CGFloat dx=停止位置.x-_位置.x;
CGFloat dy=停止位置.y-\u停止位置.y;
距离=sqrt(dx*dx+dy*dy);
}
如果(swipe.state==UIGestureRecognitizerStateEnded)
{
如果(_direction==LEFT&([UIScreen mainScreen].bounds.size.width-_startLocation.x)+distance)>[UIScreen mainScreen].bounds.size.width/2)
{
[自我重新分配CurrentImage];
}else if(_direction==RIGHT&&u startLocation.x+distance>[UIScreen mainScreen].bounds.size.width/2)
{
[自我重新分配CurrentImage];
}否则
{
//由于未应用过滤器,请将其回滚
如果(_方向==左)
{
_pictureFilterIterator=[NSNumber numberWithInt:[\u pictureFilterIterator intValue]-1];
}否则
{
_pictureFilterIterator=[NSNumber numberWithInt:[\u pictureFilterIterator intValue]+1];
}
}
[自清晰图像];
_ReassignncomingImage=是;
返回;
}
CGPoint-velocity=[滑动速度视图:self.view];
如果(velocity.x>0)//正确
{
如果(!\u指定的方向)
{
_directionAssigned=是;
_方向=右;
@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
@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))
}