Implementation of the image editor in the autolayout Environment

Source: Internet
Author: User

In most apps (especially social networking, such as QQ), there are often scenarios where the Avatar is changed: Click the user

Load the Avatar and the system image. After you click to select an image, you can scale down and

Drag to change the area of the image enclosed in the circular crop box. For example, the QQ Avatar selection and editing page is as follows:


Figure 1. QQ photo editing page

You can zoom in, zoom out, and drag the image on the page. The white ring area indicates that the image will be clicked

Crop range. Qq always ensures that the ring is completely covered by the image.

Or scale down the black area outside the image to enter the ring, and the image will automatically pop back to completely overwrite it.

In view of the limit of 2 MB for csdn to upload images, the above GIF image is very short, and interested users can open

QQ can experience it by yourself (in the personal Avatar modification function ).

Now we need to implement an interface with similar functions, in the autolayout environment

Holding landscape screens is more complicated than QQ's image selection page: QQ only supports landscape screens, no need

Consider the landscape and landscape switching issues. The following is a detailed description.

I. Expected results

You can select or take a photo from an album or camera and load it to the image editing page.

Move or scale down a photo so that an appropriate image is displayed in the circle selection box as the user's profile picture. Such

Description:

When dragging and scaling, you must ensure that all the ring areas are covered by images so that the cropped

The photo just fills the entire circular area. At the same time, because we support horizontal screen layout, make sure that

After the landscape screen is switched (or vice versa), the ring is still in the correct area.

Figure 2. Landscape Effect



Figure 3. Landscape Effect

The entire interface meets the above user interaction requirements. When you click OK

You can crop an image in a region to edit the image.

II. Implementation Details 2.1 Basic Ideas

In terms of implementation, this page can be divided into two major parts: one is the scrollview settings: contentsize,

Contentinset, zoomscale, and so on; the other is the implementation of the cut box (White Ring, peripheral translucent mask)

Layer), and how the cut box changes when switching between the horizontal and vertical screens; and the two are not completely independent: scrollview

Many interactions depend on the cut box: the minimum scale-down cannot be smaller than the cut box, and the Movement cannot exceed the cut box's range.

Perimeter. It can be considered that the attributes of scrollview depend on the attributes of the cut box. While the cut box is on the horizontal or vertical screen

The size and position remain unchanged. Therefore, we naturally get the idea: Determine the cut first.

Box, the screen is OK, and then confirm the scrollview through the cut box.

2.2 Implementation of the cut box

From the figure 2, we can see that the cut box is a special interface: the inside of the circular dotted box is completely transparent.

(Clearcolor or alpha = 0), while the filling Area of the periphery is semi-transparent (blackcolor and

Alpha = 0.2), normally set Alpha, backgroundcolor, and layer. cornerradius through nested View

No, because the Alpha attribute of the view is "hereditary": the Alpha of the parent view directly acts on all

In this case, we need to consider using a lower-level drawing method to directly cut a view.

Draw the box.

We add a view (called maskview) to the storyboard and add constraints to make it and scrollview

The size and size are completely consistent. Change the class of this view to ttphotomaskview: one of ours

Custom view: In the drawrect method, draw a cut box as follows:


Figure 4. Create a cut box

1. Draw two closed lines, one of which is square, just covering the border of the entire view, and the other is a circle.

Dotted Line cropping box;

2. Use the parity principle to fill the two closed curves with colors to make the area between the box and the circle box

Fill (black, alpha = 0.2), while the inside of the circle is not filled (transparent ).

The specific implementation code is as follows:

<span style="font-size:18px;">-(void)drawRect:(CGRect)rect{    CGFloat width = rect.size.width;    CGFloat height = rect.size.height;    //pickingFieldWidth:圆形框的直径    CGFloat pickingFieldWidth = width < height ? (width - kWidthGap) : (height - kHeightGap);    CGContextRef contextRef = UIGraphicsGetCurrentContext();    CGContextSaveGState(contextRef);    CGContextSetRGBFillColor(contextRef, 0, 0, 0, 0.35);    CGContextSetLineWidth(contextRef, 3);    //计算圆形框的外切正方形的frame:    self.pickingFieldRect = CGRectMake((width - pickingFieldWidth) / 2, (height - pickingFieldWidth) / 2, pickingFieldWidth, pickingFieldWidth);    //创建圆形框UIBezierPath:    UIBezierPath *pickingFieldPath = [UIBezierPath bezierPathWithOvalInRect:self.pickingFieldRect];    //创建外围大方框UIBezierPath:    UIBezierPath *bezierPathRect = [UIBezierPath bezierPathWithRect:rect];    //将圆形框path添加到大方框path上去,以便下面用奇偶填充法则进行区域填充:    [bezierPathRect appendPath:pickingFieldPath];    //填充使用奇偶法则    bezierPathRect.usesEvenOddFillRule = YES;    [bezierPathRect fill];    CGContextSetLineWidth(contextRef, 2);    CGContextSetRGBStrokeColor(contextRef, 255, 255, 255, 1);    CGFloat dash[2] = {4,4};    [pickingFieldPath setLineDash:dash count:2 phase:0];    [pickingFieldPath stroke];    CGContextRestoreGState(contextRef);    self.layer.contentsGravity = kCAGravityCenter;}</span>
Now let's look at how to deal with the problem of horizontal and vertical screens: Our cut box is directly through the drawrect of the uiview

The method is hand-drawn directly, so it is impossible to re-layout the cut box through autolayout.

The solution is to re-draw a circular cut box when switching between the screen and the screen. Do not enable

Use willrotatetointerfaceorientation :( uiinterfaceorientation) tointerfaceorientation

Duration :( nstimeinterval) duration to get the screen rotation event.

Willtransitiontotraitcollection :( uitraitcollection *) newcollection

Withtransitioncoordinator :( id <uiviewcontrollertransitioncoordinator>) Coordinator

. Therefore, in this method, force the cropping frame to be repainted (maskview ):

<span style="font-size:18px;">#pragma mark - UIContentContainer protocol- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator{    [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];    [self.maskView setNeedsDisplay];}</span>
In this way, the cut box is successfully completed. Next we will set the scrollview to satisfy my needs.

Interaction expectations.

2.3scrollview settings

First, let's take a look at the hierarchical structure of the entire view: scrollview has

Imageview is the content view of scrollview. A view with a cut box is placed on the scrollview.

(Mask view), both of these three views maintain consistency with the bounds of the Root View through constraints.


Figure 5. View hierarchy

As mentioned above, the settings of various attributes of scrollview depend on the hand-drawn cut box. The Circle

The position and size of the cut box may change after each screen conversion. Therefore, we must

After the drawrect method of is called, the attributes of scrollview are adjusted again. Therefore, in the maskview

Add a proxy to set this proxy to the viewcontroller where the maskview is located.

When this happens, the viewcontroller is notified via proxy to adjust the attributes of scrollview:

<span style="font-size:18px;">//  TTPhotoMaskView.h@protocol TTPhotoMaskViewDelegate <NSObject>- (void)pickingFieldRectChangedTo:(CGRect) rect;@end@interface TTPhotoMaskView : UIView@property (nonatomic, weak) id <TTPhotoMaskViewDelegate> delegate;@end</span>
In the drawrect method of maskview, add: pickingfieldrect is the ring shear box.

Contains the origin and size information relative to the maskview.

<span style="font-size:18px;">    if ([self.delegate respondsToSelector:@selector(pickingFieldRectChangedTo:)]) {        [self.delegate pickingFieldRectChangedTo:self.pickingFieldRect];    }</span>

The following is how to implement the pickingfieldrectchangedto method in our viewcontroller,

Adjust scrollview:

<span style="font-size:18px;">#pragma mark - TTPhotoMaskViewDelegate- (void)pickingFieldRectChangedTo:(CGRect)rect{    self.pickingFieldRect = rect;    CGFloat topGap = rect.origin.y;    CGFloat leftGap = rect.origin.x;    self.scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(topGap, leftGap, topGap, leftGap);    //step 1: setup contentInset    self.scrollView.contentInset = UIEdgeInsetsMake(topGap, leftGap, topGap, leftGap);    CGFloat maskCircleWidth = rect.size.width;    CGSize imageSize = self.originImage.size;    //setp 2: setup contentSize:    self.scrollView.contentSize = imageSize;    CGFloat minimunZoomScale = imageSize.width < imageSize.height ? maskCircleWidth / imageSize.width : maskCircleWidth / imageSize.height;    CGFloat maximumZoomScale = 5;    //step 3: setup minimum and maximum zoomScale    self.scrollView.minimumZoomScale = minimunZoomScale;    self.scrollView.maximumZoomScale = maximumZoomScale;    self.scrollView.zoomScale = self.scrollView.zoomScale < minimunZoomScale ? minimunZoomScale : self.scrollView.zoomScale;    //step 4: setup current zoom scale if needed:    if (self.needAdjustScrollViewZoomScale) {        CGFloat temp = self.view.bounds.size.width < self.view.bounds.size.height ? self.view.bounds.size.width : self.view.bounds.size.height;        minimunZoomScale = imageSize.width < imageSize.height ? temp / imageSize.width : temp / imageSize.height;        self.scrollView.zoomScale = minimunZoomScale;        self.needAdjustScrollViewZoomScale = NO;    }}</span>
Next we will explain in detail the role of each step above. First, we will use an official Apple document (scroll

View programming guide for iOS ).

Significance and role:

Figure 6. The contentsize and contentinset attributes of uiscrollview

Contentsize is the size of the content you want to display in scrollview. The specific value must be the root

Based on the size of the content, we want to completely display the content of an image without compression.

In step 2, set contentsize to the same size of the image (image. size.

Contentinset can be understood as the gap between the top, bottom, left, and right sides of the displayed content. The default value is (0, 0,

0, 0), contentinset indicates that the white space plus contentsize is what a scrollview can slide.

All regions. Here we do not want to let the sliding area of the content (image) go beyond the position of the circular cut box.

The gap between the frame ring and the top, bottom, and left edges of the view is cleverly used as the contentinset of the scrollview,

This is what step 1 does. It ensures that the circular cut box can always fill the image when the finger is dragged on the image.

.

Scrollview supports zoom-in and zoom-out. You only need to set the maximum and minimum multiples of the scale-in,

Then in the proxy function (uiview *) viewforzoominginscrollview :( uiscrollview *) scrollview

Returns the view to be scaled. Here, we need to determine the minimum scale Size of scrollview to be full.

The dimension (long or wide) That is scaled down to the shorter part of the image and is tangent to the circular shear frame.

The minimum value of scale-down is enough, because the cut box cannot be filled if the image is scaled down:


Figure 7. scale down to the hour, the cut box must be tangent to the shorter side

Step 4 is only executed during viewdidload, that is, when you enter the image editing page for the first time,

You need to force adjust the current zoomscale of scrollview to display the image in a proper size.

.

So far, the entire function has been completed, run the program, and check the effect, as expected:


Figure 8. Screen Rotation


Figure 9. Drag and zoom

Iii. Summary

Load the image into the scrollview, scale it down, drag it, And then crop it. Part of it is the image editor.

The main function, seemingly simple functional requirements, is everywhere, and must be considered in depth.

Make good use of the drawrect method of uiview and the scrollview features.

.

The following two examples are worth noting:

1. Implementation of the circular cut box and processing of the cut box after rotating the screen in the autolayout environment;

2. scrollview attribute settings must be combined with the actual size of the loaded image and the position of the circular cut box.

And the size information to dynamically adjust the contentsize and contentinset attributes of the scrollview.

Implementation of the autolayout environment slice Editor

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.