|
最近在项目有遇到图片打标签的需求,即在图片上面添加相关标签(标签可移动、删除),然后生成一张新的图片,上传到服务器上。下面就来谈谈我的实现方式吧,如果你有更好的方法,麻烦告诉我,THX。 实现过程我的思路是:Pan手势拖动标签;LongPress手势显示“删除”ItemMenu,点击删除item删除标签;新图片屏幕截图生成;图片展示在画布的方式自适应。首先将标签自定义一个View。
7 `* i2 q* ^+ e- F" y& |- |! ~2 X - #import <UIKit/UIKit.h>; W. h' a. H2 Z! f. ?. k/ W8 [
- 0 U9 u" S- e9 {9 R
- /// 通知$ e& Z) F! \* t
- extern NSString *const DDAnnotationViewDeleteNotifation;4 Y# L; M* J" W
- /// 距离父视图的边缘 u! J5 u" b* v
- #define marginSupView 5.0, `5 h$ n9 r y ?7 N
- ! e( Y" ^, a' P: D
- /**
* X! ~- w! \- _$ B$ | - * UIImageView上的标注视图 m1 W) [5 p4 p* m, |2 a# H: D
- */2 {; n' U0 M5 H8 n+ i- {
- @interface DDAnnotationView : UIView
% \4 M9 M" Z2 G1 T - $ x* f! @0 C& \3 Y* I* W; b5 c% r
- /**
. l A- R# h. u2 u* r - * 根据Image Frame 布局
! u5 J; B- a4 \( }1 C - *
! s2 D2 ?* `2 r$ Q0 s7 J3 M1 Z - * @param frame <#frame description#>
6 p1 q5 u: a9 f( h - * @param details <#details description#>8 H2 R1 x/ u- T
- */2 e' H1 I G1 u+ O7 E3 q
- - (void)layoutAllElement:(CGRect)frame details:(NSString *)details;
3 m% i9 k# C6 E
# t, s4 U$ V" D- L( ?6 ?; l+ d) x- @end
复制代码- #import "DDAnnotationView.h"
+ m" f+ V* B" t* _% V9 W Z5 v- s - & {- I3 R6 f y2 a/ p5 D5 P6 e
- NSString *const DDAnnotationViewDeleteNotifation = @"DDAnnotationViewDeleteNotifation";
- t4 P: k# D( t0 {, x- F( q - ^- G% L% j. `$ S2 s `- ]
- @interface DDAnnotationView ()
- [ r0 N* |* L/ k - /**
& D% i/ o2 [! L. x - * 背景图片. e' O& e( W7 I* `& @6 H. F# j. j1 s5 V
- */
/ I4 x+ i; i8 }# L2 x5 x6 O - @property (nonatomic, strong) UIImageView *bgImageView;
! |6 e) r; O4 S4 `6 j n - /**
6 L% B# ~; a8 h! t - * 字体信息& u7 @; [9 E& V1 |, b$ ?
- */
' l0 v: x) G; d f - @property (nonatomic, strong) UILabel *textLabel;, J6 }5 Q# T0 F; I4 Y/ r
- 7 H" O7 e% t" ?! {3 z) b
- @end7 `/ y& q1 T2 ^+ v8 q" O
$ d& B! ^, m! ~* i9 r- @implementation DDAnnotationView
# ~: F; ~. B* J! `1 \( Z, j# [
! e0 k' C9 I8 ~: ]% e- - (void)dealloc {
8 c& s) ?" u$ H3 \+ h+ e, S - [self.bgImageView removeFromSuperview];
( Q, q2 J) y$ G4 e - self.bgImageView = nil;4 Y& x( ~! V7 G$ ~2 T7 M2 ]9 j
- [self.textLabel removeFromSuperview];
+ `* d7 v g% F/ Q5 n6 Z - self.textLabel = nil;
) N) }% W) ?1 e1 i! J( g: B - }! g7 F% _, G' B- P
- & n/ ~( C8 r% V+ L
- #pragma mark - init Method
5 Z: z; L1 J# o- N9 r& L' m) f: C1 T - - (id)initWithFrame:(CGRect)frame {
+ Z8 s7 f* c1 ~+ U" L - self = [super initWithFrame:frame];4 m( y6 i9 R, r4 ~0 R
- if (self) {
d3 D+ } r# w( |$ ^2 a# u' m' n - self.userInteractionEnabled = YES;
7 o/ L$ b3 o7 G! I4 A N+ Z/ C - self.clipsToBounds = YES;. E5 C8 H4 k* F; n9 z6 T' }- A
- self.bgImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
9 m8 ~5 U! K8 j! E: \4 M; r - self.bgImageView.backgroundColor = [UIColor clearColor];
6 O7 k7 m" e8 Y" `, R: N' V - [self addSubview:self.bgImageView];
# t; ]7 j% t, }2 z% s0 ?
8 v' s8 k. v4 M5 W4 e- self.textLabel = [[UILabel alloc] initWithFrame:CGRectZero];
! W; }3 ]: V2 w- A# [ - self.textLabel.backgroundColor = [UIColor clearColor];, {7 ?# G0 W: A) e; m" \' ]' r5 h
- self.textLabel.numberOfLines = 0;; h$ Z' Z: {" S r
- self.textLabel.textColor = [UIColor whiteColor];
9 |4 {7 Y6 K- S0 D7 s: H; T - self.textLabel.font = [UIFont systemFontOfSize:12.0];% I7 e( _' ?; M5 o9 _ s ~
- self.textLabel.lineBreakMode = NSLineBreakByTruncatingTail;
. M' K) c) o$ k: r3 z- {, z - [self.bgImageView addSubview:self.textLabel];% C+ r2 E) ~2 s4 s* R/ `& E' i
- }( ]8 k8 z7 B& q _
- return self;0 O& X8 ^1 g, X; {: b3 |; ~3 o2 e
- }
: b2 i& w+ J5 c8 a$ `$ l/ H1 a - 6 |/ e8 ]% k$ s, z" S* X
- /**" b; w9 z# Q6 D, `! O
- * 根据字符串调整 AnnotationView 的位置
7 J# @% e/ o! z. p% }3 V ?( r: u3 b* c - *
1 ]! n9 R1 m4 e* O% x$ t - * @param frame frame description5 @$ Q3 w; `7 q4 n% c5 u }
- * @param details details description" J3 E1 u, U' y% f
- */
0 _7 I8 d9 q: Z/ ^ - - (void)layoutAllElement:(CGRect)frame details:(NSString *)details {
, u6 \4 k* E: n- n - CGFloat originX = 25.0, kRignt = 5.0, labelWidth = 0;7 ]4 j' W9 X$ g* x
- labelWidth = frame.size.width - originX - kRignt - marginSupView;
' k! I' y/ V; N- M
k1 m4 @& X0 i$ E; |% P0 q( j- CGSize detailsSize = [details sizeWithFont:self.textLabel.font constrainedToSize:CGSizeMake(labelWidth, MAXFLOAT) lineBreakMode:self.textLabel.lineBreakMode];
* J9 l3 s W! `4 A$ f3 K - NSInteger lines = detailsSize.height / [self.textLabel.font pointSize];
! p. L7 S. P4 m* r# O& j4 e! K: b - self.textLabel.text = details;; M) f& _) U: C1 X
- if (detailsSize.width < labelWidth) {/ Q* ]7 z( @4 S5 I% \1 G% ^
- labelWidth = detailsSize.width + originX + kRignt;3 K9 R/ d: J$ @; t) m; V1 b1 q# R
- }0 Y# r7 u/ |. T( G6 p" p
- [5 ]3 z- b/ p
- NSString *backgroundName = @"Tag_background";- k, z6 H1 D, u8 u
- if (lines > 1) {8 A9 }: z/ n0 h
- // 大于1行6 v. f. c6 d a1 Y* R
- backgroundName = @"Tag_background2";* }0 h' A% n( @$ \( p2 {
- }
' v* i7 @1 L( f5 M; o: C' Z2 Y0 L - UIImage *bgImage = [DDImageManager getImageWithNameByPath:backgroundName resizable:YES];
9 I; m/ T0 ~8 g - backgroundName = nil;2 i$ O) t5 ]- q) J
- if (labelWidth <= bgImage.size.width) {
& a1 e1 t; x# d8 E4 G( F, d1 U: t - labelWidth = bgImage.size.width; g+ w& r8 A1 Q* t5 S$ Y7 M
- }
3 ?. V8 M: L& W n" j - self.bgImageView.frame = CGRectMake(0.0, 0.0, labelWidth, detailsSize.height + kRignt);' `0 l4 ]( h. c5 F* D
- self.bgImageView.image = bgImage;
" L/ z6 t- V, X1 l1 N - bgImage = nil;
: C% }1 m$ X% M# ~7 U6 u. \+ K - self.textLabel.frame = CGRectMake(originX, kRignt, detailsSize.width, detailsSize.height);
7 X- M8 j+ m5 H# l" f7 ~: B$ { - self.textLabel.yt_centerY = self.bgImageView.yt_centerY;
2 b" G6 j: o5 R, n8 ~7 C+ i - self.frame = (CGRect){frame.origin, self.bgImageView.yt_width, self.bgImageView.yt_height};! g/ d$ q8 \8 P7 s5 m t$ X
; u) A% B$ N# W. `- // 长按手势
! w5 }5 h0 `, F0 G# Z - UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGesture:)];4 B& [$ m9 H; y, T
- [self addGestureRecognizer:longPress];
+ M! b- X2 E! Q/ f) r - longPress = nil;( I! C' ]' \ s- t. r' Z
+ ~+ A, V6 t* O A4 o7 `: g! C- // 拖动手势7 m. z7 u2 c, p( c
- UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];' m8 f. i) h( g* M& c
- [self addGestureRecognizer:panGestureRecognizer];
6 p2 e2 M- S$ n. Z+ x$ m - panGestureRecognizer = nil;
; F0 w# L8 V% R& A( \: n - }
+ D( R1 K# o5 U) ^2 s - ! t' _, k# z2 q' @
- #pragma mark - 长按删除操作* b% D8 N% U; c! \ Q2 {& C0 A9 l
- - (BOOL)canBecomeFirstResponder {
& ]4 v. M# C! O/ G8 A - return YES;7 e* i& e0 V7 v. C$ t- y+ h t
- }# D: S- X. d# J, \! v' M
- 4 T6 K: O" z7 ^" v: O1 |. P
- - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {& A3 P* [, | t2 ]
- return (action == @selector(deleteMethod:));
' k; K) f) `5 m/ a \! R - }2 n+ U! j Y6 ]3 z2 F
- 9 b* G) W" O+ v; ~7 l \* t
- - (void)showDeleteMenu {3 o- |" p( `* n: N
- [self becomeFirstResponder];
# e- ~6 ^* I6 p - UIMenuController *menuController = [UIMenuController sharedMenuController]; X3 z4 B) A7 O1 N
- UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:@"删除" action:@selector(deleteMethod:)];1 _& U2 t+ C; ^1 i
- menuController.menuItems = @[copyItem];3 d* ^' ?( N, _* B
- [menuController setTargetRect:self.frame inView:self.superview];! b& X5 q7 }6 \4 b8 R3 [
- [menuController setMenuVisible:YES animated:NO];
2 M- }# F$ Q+ T7 U w9 d- t# r! T4 Y - menuController = nil;- d4 U2 h6 E. f1 G4 Q3 d6 Y
- }& V; U6 X) d4 x% P6 D$ }+ H1 B
" c( ~5 X% ~1 @& I: ` K3 ~: C- /**
& v: y- i* l4 ?/ b5 M3 C - * 删除 方法
# x9 j3 q9 s- M+ _2 l z* \ - *
3 Y' B9 j2 o0 g0 m9 ~; H+ @ - * @param sender <#sender description#>
3 K& O$ F9 O! ?! { - */
1 E- a8 k; Z$ ]- L4 K; n$ @& P+ O7 Z0 p - - (void)deleteMethod:(id)sender {
5 t) }' N& L" V2 R - if ([self superview]) {* E0 F/ ~7 s" j! ]; r
- [self removeFromSuperview];) P8 s \7 C% G3 ~
- // 发送通知- y5 W4 F. {# q6 c3 D: E
- [[NSNotificationCenter defaultCenter] postNotificationName:DDAnnotationViewDeleteNotifation object:nil]; b9 J; x8 ~0 {0 B7 u8 H: O
- }
# h8 c4 O- f% ^) |& h2 _( \ - }
: H3 N2 b: L* l3 i- J! }0 s7 l - 1 I/ D: R- n/ q/ S: Z3 ?8 S
- /**
) p! \( q8 I# x6 _ - * 长按手势- C# ^2 U0 R/ V$ K' j" e/ H" G
- */ O7 g, a2 m7 t) g' \
- * @param longTap longTap description
8 }8 V; f" ~( g, t* h. D - */
1 s6 X0 m4 b" N! X0 v! p- o/ [ - - (void)longPressGesture:(UILongPressGestureRecognizer *)longTap {
1 t: t6 d- v" |, B: g4 ?- @2 J - if (longTap.state == UIGestureRecognizerStateEnded) {# Q5 M( I, q- L H b
- return;9 ~: B9 R7 v9 ?) D+ c
- }
+ R( g; o" @7 W5 }2 K2 B5 c - CGRect tmpRect = self.frame;
' T9 r: g0 O/ f( u1 x s - if (tmpRect.size.height != 0) {
; ?' Z& a+ D3 k$ R' e: c - [self showDeleteMenu];
2 X/ v3 S. U: e: [) R - }
) b! g/ e y5 e6 T, ~ - }
0 j2 c6 Y/ n1 D: a4 ^& b - ! a. u* |& e0 T
- /**" K( q) j8 F. D+ Q9 @2 b
- * 拖动手势
* m, a$ W; X2 B3 o: ^ ^1 s - *
8 `+ h# `5 s3 l - * @param panTap panTap description9 }" C( g5 X0 O) Y
- */
! |" X, u8 J$ T: `: z - - (void)handlePanGesture:(UIPanGestureRecognizer *)panTap {1 f$ E* t" ~/ q9 l
9 ^$ q( t! a9 ^2 E5 @ S- UIView *panView = panTap.view;& |- y7 b6 b3 l$ l1 t2 W/ `6 h; b
- CGPoint translation = [panTap translationInView:panView];
# X* @1 T# w5 o' s8 `, l! N6 u - CGPoint newCenter = CGPointMake(panTap.view.center.x + translation.x, panTap.view.center.y + translation.y);! g. ^7 f, m/ {8 ^
- // 设置拖动范围
, \. c }- _, R0 [ - if ((newCenter.y >= panView.yt_height / 2) && (newCenter.y <= panView.superview.yt_height - panView.yt_height / 2) && (newCenter.x >= panView.yt_width / 2) && (newCenter.x <= panView.superview.yt_width - panView.yt_width / 2)) {
( B) D' n x; j# s - panTap.view.center = newCenter;: w0 g, P V' J2 n% P9 w
- [panTap setTranslation:CGPointZero inView:panView.superview];
7 f6 j4 @2 r9 G! y3 T6 u# d& ^
' V6 U7 `& r0 G3 H; G8 C- UIView *sonView = nil;: ^& M6 \0 ^! j3 V* L: [0 l7 w
- if ([[self.superview subviews] count] > 0) {
- l6 K" o: Z: E' K - sonView = [[self.superview subviews] lastObject];6 F* Q/ v* _! S9 H5 f! W
- if (sonView && sonView != self) {
" }( G5 J# \" M3 Z( Q - //放到最前面
X9 P$ e! V+ M( k; G - [self.superview bringSubviewToFront:self];
6 Q. R( ~8 A4 K0 m' C" v - }7 I7 x% ^3 o) V- ]' K
- }0 ~: M* Y- K4 v
- }
' x. a( _# J6 N4 K' u* x - }
复制代码
- V% ~0 K6 W$ p( _. T0 A好了,标签控件已经封装好了,现在的问题是图片有大有小呀,那该怎么显示?产品那边要求,在保证图片不拉伸的情况下,图片至少一边充满屏幕(要么上下充满、要么左右充满)。我是这么做的,首先,我获得Image数据后,不管怎么样都将图片缩放至我的画布大小(里面的逻辑应该是,如果图片宽带超过画布宽度,图片高度小于等于画布高度,则按照画布宽度缩放。以此类推)。缩放方法如下(UIImge 的 Category)。: R# }% U5 ?1 J D7 P% y
- - (UIImage *)zoom:(CGSize)size {
% |* N! X( ^8 ~) B4 ~4 R - CGSize imageSize = self.size;
& D' L! S* V0 V: ? - CGFloat width = imageSize.width;
/ D; v7 b5 H) x! {6 R - CGFloat height = imageSize.height;+ q3 a V3 c$ b( V
-
) `9 n0 r4 C) C, b1 r* ?1 U - if (width <= size.width && height <= size.height) {2 c( N8 Y, ^6 L: {
- return self;
" ~ k: \- l: @" @" T! R - }
3 Z& c. M8 K4 a4 n - if (width == 0 || height == 0) {1 _7 n, W U& Q3 y( V& d# n
- return self;" B8 v! a8 o9 B7 _/ L6 O6 q+ z# U
- }' f: {. j6 A4 ]5 L
- 7 n; Q* i! h- E5 N5 ~4 y+ _% r
- UIImage *newImage = nil;) t+ _: c; G: Q: b! H9 k: H% j
- CGFloat widthFactor = size.width / width;# d; ^1 S" q4 M) [8 q& [0 l" k
- CGFloat heightFactor = size.height / height;+ j; E4 k8 A% ?1 B; O# a3 T4 M# m
- CGFloat scaleFactor = 0.0;
- Y6 D0 s, w4 _& Y - M' C" A4 S1 P8 f- ?
- if (widthFactor > heightFactor){
4 S/ S9 d. v& _4 j - scaleFactor = heightFactor; * N3 P A+ [$ p$ p$ P2 n1 P& ]
- } else {
) o8 P3 }' ?" ]8 N - scaleFactor = widthFactor;
5 h% Q; i/ `$ X# Z) U, u# {! J5 q0 j - }* m9 a1 a( ~4 Q/ V: q
-
! e, a% y5 { X, R: i0 d1 i2 m - CGFloat scaledWidth = width * scaleFactor;
0 r0 `% j9 [- E+ m+ F4 I6 X - CGFloat scaledHeight = height * scaleFactor;0 L; v1 W/ W9 G! Z, K5 R3 ^8 D' ]
- CGSize newtargetSize = CGSizeMake(scaledWidth, scaledHeight);! E1 @, t& p7 O& `; @2 R
- UIGraphicsBeginImageContext(newtargetSize); 1 E; [& j! a; g) K% l0 U
-
" m1 i" R& `$ O6 S- A9 m* V - CGRect thumbnailRect = CGRectZero;
) b' r& f" L: i, K - thumbnailRect.size.width = scaledWidth;
2 w: B' n+ A4 z& e" l, _ - thumbnailRect.size.height = scaledHeight;
- A! \' w% {" [" p7 K4 D- } -
; ?- j' E0 O, r - [self drawInRect:thumbnailRect];( T6 c2 v; ~& |# ^
- newImage = UIGraphicsGetImageFromCurrentImageContext();7 N" k+ X9 p" ^1 I6 _+ I+ C
-
4 a& l* F2 c8 X0 A( K/ j - UIGraphicsEndImageContext();
; N! A2 M6 }5 N3 B, b5 z - return newImage;
?' b! ~6 W: ~2 C7 j+ k - }
复制代码截图方法很简单,因为标签添加在UIImageView上面,只要截图UIImageView即可。截图方法如下:/ m* ~, o0 B# T+ R& ]" V
- - (UIImage *)screenCapShowImage:(UIView *)tagView {
; I5 M- E- m5 E0 c+ l, ` - CGFloat scale = [[UIScreen mainScreen] scale];8 p$ V+ ~8 F% h! i: p3 q% d5 h/ V
- CGRect viewFrame = tagView.frame;3 z4 ~1 o5 C: |1 R
- if (scale > 0.0) {
: u0 t' J1 m" z2 Q - UIGraphicsBeginImageContextWithOptions(viewFrame.size, NO, scale);
4 V( d U' c2 S) M - } else {& m C/ e4 ~8 }1 D8 g
- UIGraphicsBeginImageContext(viewFrame.size);# O' o% d5 `8 B: V! `
- }
5 a: }1 {+ y$ t% p- e - [tagView.layer renderInContext:UIGraphicsGetCurrentContext()];$ ?2 L' r! I3 O& O* A/ F3 A
- UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
* J/ L% f* |. _% r" p1 M - UIGraphicsEndImageContext();
! F. ^8 T f' @% _ - return theImage;
) u" A; d2 U% a! H9 X3 { - }
复制代码 总结综上所述,这个功能的实现还是比较简单的,只要思路能行的通,实现过程中的一些问题基本上Google可以解决。 参考链接& C& ~, i, @. y: F
|