📜 ⬆️ ⬇️

Development of a component for creating collages

The popularity of photo processing applications is constantly growing. Recently, we offered our readers a guide for beginners to write their own photo editor. Today we would like to share with habrovchanami the experience of our partners - developers of the company New Technologies - obtained in the course of the update of their application. This material can be useful both when working with a photo editor application and with projects in which image processing is a side function (in fact, in the case that will be discussed, this is how it was).

“In the course of designing My Wardrobe , applications for storing a collection of clothes and images, our team repeatedly had to deal with the convenience of the interface: to find a balance between a variety of functions and ease of access to them. In addition to storing all the clothes from his wardrobe, the user was given the opportunity to create an image from a combination of things and attach a photo to it. However, at the design stage, it was clear that the user might not want to take a new photo of his image, but would prefer to create an icon from photos of clothes, placing them on a solid background - this is an established practice of image imaging in the fashion world.


')
Adding this feature required the implementation of a mechanism for creating and editing collages. And since such functionality is often required in various products for working with photos, it was decided to implement it as a universal component with a simple software interface.

Formulation of the problem


The task is to provide the user with the following functions:



It should be immediately noted that an attempt to present all the editing possibilities on one screen at once can lead to both incorrect interface and technical difficulties of implementation. But, if you carefully bypass possible interaction collisions, you get a user-friendly interface without unnecessary elements.

Implementation


To implement this interface, 2 controllers (UIViewController) were created: a collage controller and a collage element controller . At the same time, the Collage controller can contain any configuration of containers with elements.


At this stage, this configuration will be enough.

The collage controller interface will also be fairly simple: a delegate and a method for receiving pictures from the client.

@protocol CollageVCDelegate; @interface CollageVC : UIViewController @property (weak, nonatomic) id<CollageVCDelegate> delegate; - (void)imageForIndex:(NSUInteger)index image:(UIImage*)image; @end @protocol CollageVCDelegate <NSObject> - (void)collageVCNeedsImageForIndex:(NSUInteger)index sender:(CollageVC*)sender; @end 

Obtaining an image of the finished collage is a separate task, so at this stage this function is not included in the interface.

Rotate, move, enlarge images inside the collage element


These features are implemented in the collage element controller . All image movements are made using UIGestureRecognizer. It is enough to place in the controller View and add 3 gesture recognizers to it: UIRotationGestureRecognizer. UIPinchGestureRecognizer, UIPanGestureRecognizer.

 -(void)addGestureActions:(CollageImageView*)view{ UIRotationGestureRecognizer* rotationGestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotate:)]; UIPinchGestureRecognizer* pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)]; UIPanGestureRecognizer* panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; [self.imageFrameView addGestureRecognizer:rotationGestureRecognizer]; [self.imageFrameView addGestureRecognizer:pinchGestureRecognizer]; [self.imageFrameView addGestureRecognizer:panGestureRecognizer]; panGestureRecognizer.cancelsTouchesInView = NO; panGestureRecognizer.maximumNumberOfTouches = 1; rotationGestureRecognizer.delegate = self; pinchGestureRecognizer.delegate = self; panGestureRecognizer.delegate = self; } 

They will call methods in which the appropriate affine transformations will be carried out for moving elements.

Ability to swap pictures


The function of rearranging 2 images to each other’s place will be performed at the level of the Collage Controller .

To do this, he must also track the user's gestures. To initiate the process of rearrangement, it is enough to track the moment when the user, moving the image, moved his finger to the area with another image. For this purpose, UIResponder methods have been used that pass UITouches.

Since UITouches are captured using UIGestureRecognizer in collage element controllers , they need to set the cancelsTouchesInView = NO property. This is sufficient to do only for UIPanGestureRecognizer, since you only need to track UITouches associated with moving the picture.

Events touches can be triggered by simultaneously clicking on different areas of the collage, so you need to eliminate the handling of unnecessary events. This can be done by saving the pointer to the element of the collage with which the interaction is conducted in the method touchesBegan: withEvent:

 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ UITouch* touch = [touches anyObject]; CGPoint location = [touch locationInView:self.view]; [collageItems enumerateObjectsUsingBlock:^(CollageItem * object, NSUInteger idx, BOOL *stop) { //       if ([object.imageFrameView pointInside:[self.view convertPoint:location toView:object.imageFrameView] withEvent:event]) { [self startedInteractionInItem:object]; *stop = YES; } }]; } - (void)startedInteractionInItem:(CollageItem*)item{ if (interactingItem == nil) { interactingItem = item; } } 

The touchesMoved method calls to check if the user wants to swap pictures. Here you need to determine whether the user has moved the image to another element of the collage. If this happens, you need to remember the current state of the elements of the collage and display the result of the permutation of images to the user. If after that the user again placed the image in the start area, you need to return the state of the elements back.

 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ UITouch* touch = [touches anyObject]; CGPoint location = [touch locationInView:self.view]; if ([touch.view isEqual:interactingItem.imageView] || interactingItem == nil) { [collageItems enumerateObjectsUsingBlock:^(CollageItem * object, NSUInteger idx, BOOL *stop) { if ([object.imageFrameView pointInside:[self.view convertPoint:location toView:object.imageFrameView] withEvent:event]) { [self processInteractionInItem:object]; *stop = YES; } }]; } } - (void)processInteractionInItem:(CollageItem*)item{ if ([interactingItem isEqual:item]) { if (swapTargetItem) { [self cancelSwap]; } } else { if (![swapTargetItem isEqual:item]) { [self prepareSwapWith:item]; } } } 

In the touchesEnded: withEvent: method, the state is applied after the images are swapped, the pointer to the interaction element is released.

 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ UITouch* touch = [touches anyObject]; CGPoint location = [touch locationInView:self.view]; if (interactingItem) { if ([touch.view isEqual:interactingItem.imageView]) { [collageItems enumerateObjectsUsingBlock:^(CollageItem * object, NSUInteger idx, BOOL *stop) { if ([object.imageFrameView pointInside:[self.view convertPoint:location toView:object.imageFrameView] withEvent:event]) { [self finishedInteractionInItem:object]; *stop = YES; } }]; } } } - (void)finishedInteractionInItem:(CollageItem*)item{ if (![interactingItem isEqual:item]) { [self applySwap]; } [self unlockItems]; interactingItem = nil; } 

Thus, we avoid the conflicts of processing different gestures.

Conclusion


At the exit, we have an interface for easy creation and editing of collages.
When using an editor designed in this way, there is no collision between gestures, the control is intuitive, and the absence of unnecessary buttons and screen states makes it easier for the user to interact with the application. We plan to improve the resulting component and further implement it in other projects of the company. ”

Source: https://habr.com/ru/post/326940/


All Articles