//
// TouchMoveScaleView.h
// TouchMoveScaleDemo
//
// Created by jimney on 07/05/10.
// Copyright 2010 OpenSource. All rights reserved.
//Welcome to my HomePage In CocoaChina:http://www.cocoachina.com/bbs/u.php?action=topic
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
/*
*类说明
*此类主要实现在触摸过程中,实时控制视图动画的变换
*一点触摸移动视图,两点触摸缩放视图的动作
*实现的主要思路:因为动画的过程是连贯的,在变化的过程中,
*不能直接去获得过程中的值,不连续的动画控制比较难
*因为虽然图片视图的大小或者位置发生改变时,但是视图本身的数据并没变化
*所以采用人为跟踪动画变换过程,将此时所表现在视图界面中的动画变化后的虚拟值,
*保存在相应的变量中
*/
//!补充:虚拟机中使用多点触摸,按住ALT键,可显示两个触摸点,点击移动即可看到效果
@interface TouchMoveScaleView : UIView
{
UIImage*originImage;
UIImageView*imageView;
CGFloatimageWidth;
CGFloatimageHeight;
// 跟踪图片在屏幕显示区域的原点位于整个图片的位置
CGPointmaskOriginPoint;
// 跟踪缩放后图片相对于原始图片的比例大小
CGSizescaleSize;
// 动画移动及缩放图像
CGPointfirstStartTouchPosition;
CGPointsecondStartTouchPosition;
CGFloatinitialDistance;
// 动画放缩后,原始图片变化比例
CGFloatanimationFinalScal;
}
@property(nonatomic)CGPointmaskOriginPoint;
@property(nonatomic,retain)UIImage*originImage;
@property(nonatomic)BOOLisDragAble;
// 初始化视图
- (id)initWithFrame:(CGRect)frame image:(UIImage*)image;
// 根据touch 的亮点距离变化,改变图片的大小
- (CGFloat)scaleAmount: (CGFloat)delta;
// 计算两个点之间的距离
- (CGFloat)distanceBetweenTwoPoints:(CGPoint)fromPoint toPoint:(CGPoint)toPoint;
@end
//
// TouchMoveScaleView.m
// TouchMoveScaleDemo
//
// Created by jimney on 07/05/10.
// Copyright 2010 OpenSource. All rights reserved.
//Welcome to my HomePage In CocoaChina:http://www.cocoachina.com/bbs/u.php?action=topic
#import "TouchMoveScaleView.h"
@implementation TouchMoveScaleView
@synthesize maskOriginPoint;
@synthesize originImage;
/*
*通过传入视图大小和原始图像,初始化视图
*同时设置图片动画初始数据
*/
- (id)initWithFrame:(CGRect)frame image:(UIImage*)image
{
if ((self = [superinitWithFrame:frame]))
{
imageWidth= image.size.width;
imageHeight= image.size.height;
//显示图像视图
originImage= [[UIImagealloc] initWithCGImage:image.CGImage];
imageView=[[UIImageViewalloc] initWithImage:originImage];
imageView.frame = frame;
[selfaddSubview:imageView];
// 使图片视图支持交互和多点触摸
[imageViewsetUserInteractionEnabled:YES];
[imageViewsetMultipleTouchEnabled:YES];
// 移动初始距离
initialDistance = -1;
// 动画缩放比例数据
// 缩放后可见动画视图的原始位置坐标
maskOriginPoint.x=maskOriginPoint.y = 0;
// 缩放后可见动画视图的大小
scaleSize= originImage.size;
// 缩放后可见动画视图的相对于原始图片比例
animationFinalScal=1.0;
// 动画缩放控制标志
//imageView.transform = CGAffineTransformIdentity;
}
returnself;
}
// 定义一个静态全局变量,跟踪两次touch
static UITouch *g_firstTouch = nil;
static UITouch *g_secondTouch = nil;
/*
*跟踪记录触摸开始的事件,并设置触摸相关的数据
*/
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// touch move image in view
{
// 两点先后触摸和同时触摸
if([touches count] < 2)
{
// first time single touch
if (g_firstTouch == nil && g_secondTouch == nil)
{
g_firstTouch= [[touches allObjects] objectAtIndex:0];
firstStartTouchPosition= [g_firstTouchlocationInView:imageView];
initialDistance= -1;
}
else// 当有个点已经在屏幕时,设置第二点触摸点
{
if(g_firstTouch == nil)
{
g_firstTouch= [[touches allObjects] objectAtIndex:0];
firstStartTouchPosition= [g_firstTouchlocationInView:imageView];
}
else
if(g_secondTouch == nil)
{
g_secondTouch= [[touches allObjects] objectAtIndex:0];
secondStartTouchPosition= [g_secondTouchlocationInView:imageView];
}
initialDistance= [selfdistanceBetweenTwoPoints:firstStartTouchPosition
toPoint:secondStartTouchPosition];
}
}
else//if([touches count] == 2)
{
// multi touch
g_firstTouch= [[touches allObjects] objectAtIndex:0];
g_secondTouch= [[touches allObjects] objectAtIndex:1];
firstStartTouchPosition= [g_firstTouchlocationInView:imageView];
secondStartTouchPosition= [g_secondTouchlocationInView:imageView];
initialDistance= [selfdistanceBetweenTwoPoints:firstStartTouchPosition
toPoint:secondStartTouchPosition];
}
#ifdef DEBUG
//NSLog(@"g_firstTouch = %@", g_firstTouch);
//NSLog(@"g_secondTouch = %@", g_secondTouch);
//NSLog(@"firstStartTouchPosition = (%f, %f)", firstStartTouchPosition.x, firstStartTouchPosition.y);
//NSLog(@"firstStartTouchPosition = (%f, %f)", secondStartTouchPosition.x, secondStartTouchPosition.y);
//NSLog(@"initialDistance = %f", initialDistance);
#endif
}
}
/*
*在触摸移动事件中,根据一点触摸,移动视图
*两点同时触摸,视图做缩放变化
*/
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
{
UITouch *touch1 = [[touches allObjects] objectAtIndex:0];
if ([touches count] == 1 && (g_firstTouch == nil || g_secondTouch == nil))// 只有一个点在move
{
CGPoint vectorPoint;
if (touch1 == g_firstTouch)
{
//NSLog(@"firstTouch touch move!");
CGPoint pos = [g_firstTouchlocationInView:imageView];
vectorPoint = CGPointMake(pos.x - firstStartTouchPosition.x, pos.y - firstStartTouchPosition.y);
}
elseif (touch1 == g_secondTouch)
{
//NSLog(@"second Touch touch move!");
CGPoint pos = [g_secondTouchlocationInView:imageView];
vectorPoint = CGPointMake(pos.x - secondStartTouchPosition.x, pos.y - secondStartTouchPosition.y);
}
else
{
return;
}
// 改变maskOriginPoint
// 当图片放大后,在屏幕上滑动距离的实际值改变,应该是* animationAllScal,这很重要
maskOriginPoint.x -= vectorPoint.x * animationFinalScal;
maskOriginPoint.y -= vectorPoint.y * animationFinalScal;
// 单点触摸移动,做动画移动变换
imageView.transform = CGAffineTransformTranslate(imageView.transform, vectorPoint.x, vectorPoint.y);
return;
}
if ((initialDistance > 0) && ([touches count] > 1))
{
UITouch *touch2 = [[touches allObjects] objectAtIndex:1];
CGFloat currentDistance = [selfdistanceBetweenTwoPoints:[touch1 locationInView:imageView]
toPoint:[touch2 locationInView:imageView]];
CGFloat movement = currentDistance - initialDistance;
CGFloat scale = [selfscaleAmount: movement];
// 两点触摸移动,做动画缩放
imageView.transform = CGAffineTransformScale(imageView.transform, scale, scale);
// x,y 缩放为整体大小变化的一半
// 遮罩区域原始位置准确
maskOriginPoint.x += scaleSize.width * (scale - 1) /2;
maskOriginPoint.y += scaleSize.height * (scale - 1) /2;
// 缩放的计算没问题
// 相对原始图片变化
animationFinalScal = imageView.transform.a;
scaleSize.width = animationFinalScal * originImage.size.width;
scaleSize.height = animationFinalScal * originImage.size.height;
//NSLog(@"move: scaleSize.width = %f, scaleSize.height = %f\n", scaleSize.width, scaleSize.height);
//当缩放图像的宽度小于屏幕时,不能缩放
#define SCALE_BACK
#ifdef SCALE_BACK
//缩放后的图像不小于屏幕
CGRect screenRect = [[UIScreenmainScreen] applicationFrame];
BOOL isScaled = NO;
scale = 1.0;
if(scaleSize.width >= scaleSize.height)
{
//NSLog(@"scaleSize.width >= scaleSize.height");
//NSLog(@"scaleSize.width = %f, scaleSize.height = %f\n", scaleSize.width, scaleSize.height);
if(scaleSize.width < screenRect.size.width)
{
scale= screenRect.size.width / scaleSize.width ;
isScaled= YES;
}
}
else
{
if(scaleSize.height < screenRect.size.height)
{
scale= screenRect.size.height / scaleSize.height ;
isScaled= YES;
}
}
// 需要恢复整屏幕大小
if (isScaled)
{
imageView.transform = CGAffineTransformScale(imageView.transform, scale, scale);
// x,y 缩放为整体大小变化的一半
// 遮罩区域原始位置准确
maskOriginPoint.x += scaleSize.width * (scale - 1) /2;
maskOriginPoint.y += scaleSize.height * (scale - 1) /2;
// 缩放的计算没问题
// 相对原始图片变化,获得当前视图的缩放后的比例
animationFinalScal = imageView.transform.a;
scaleSize.width = animationFinalScal * originImage.size.width;
scaleSize.height = animationFinalScal * originImage.size.height;
}
#endif
}
}
}
/*
* 触摸结束,重设事件相关数据
*/
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
{
// 重设touch移动的距离
initialDistance= -1;
// 重设touch事件变量
g_firstTouch= nil ;
g_secondTouch= nil;
//当只有一次touch事件时
if ([touches count] < 2 )
{
if ([[touches allObjects] objectAtIndex:0] == g_firstTouch)
{
g_firstTouch = nil;
}
elseif ([[touches allObjects] objectAtIndex:0] == g_secondTouch)
{
g_secondTouch = nil;
}
}
else
{
if ([[touches allObjects] objectAtIndex:0] == g_firstTouch)
{
// 以后用for循环替代,更好
g_firstTouch = nil;
g_secondTouch = nil;
}
}
// 在结束,动画恢复相应的移动或者缩放
// 当图片移除边界,恢复
// 当图片缩放到一定大小,恢复,此功能以后要实现
// maskImageView.size
// maskOriginPoint
// scaleSize
CGContextRef context = UIGraphicsGetCurrentContext();
[UIViewbeginAnimations:nilcontext:context];
[UIViewsetAnimationCurve:UIViewAnimationCurveEaseOut];
[UIViewsetAnimationDuration:0.5f];
CGRect screenRect = [[UIScreenmainScreen] applicationFrame];
CGRectrect = imageView.frame;
// 下面为动画缩放超过所设置大小,做动画恢复
// 注意:下面的效果没有实现,有问题,你可以修改
//#define SCALE_BACK
#ifdef SCALE_BACK
//缩放后的图像不小于屏幕
BOOL isScaled = NO;
CGFloat scale = 1.0;
if(scaleSize.width >= scaleSize.height)
{
//NSLog(@"scaleSize.width >= scaleSize.height");
//NSLog(@"scaleSize.width = %f, scaleSize.height = %f\n", scaleSize.width, scaleSize.height);
if(scaleSize.width < screenRect.size.width)
{
scale= screenRect.size.width / scaleSize.width ;
isScaled= YES;
}
}
else
{
if(scaleSize.height < screenRect.size.height)
{
scale= screenRect.size.height / scaleSize.height ;
isScaled= YES;
}
}
// 需要恢复整屏幕大小
if (isScaled)
{
// x,y 缩放为整体大小变化的一半
// 遮罩区域原始位置准确
maskOriginPoint.x += scaleSize.width * (scale - 1) /2;
maskOriginPoint.y += scaleSize.height * (scale - 1) /2;
// 缩放的计算没问题
// 相对原始图片变化
animationFinalScal*= scale;
scaleSize.width= animationFinalScal * originImage.size.width;
scaleSize.height= animationFinalScal * originImage.size.height;
rect.size= scaleSize;
}
#endif
// 此值为判断图片右边和下边到屏幕距离
CGFloat deltaX = (scaleSize.width - maskOriginPoint.x) - screenRect.size.width;
//CGFloat deltaY = (scaleSize.height - maskOriginPoint.y) - screenRect.size.height;
#ifdef DEBUG
//NSLog(@"==========================================================\n");
//NSLog(@"animationFinalScal = %f\n", animationFinalScal);
//NSLog(@"mainscreen move dist = %f\n", animationFinalScal * screenRect.size.width);
//NSLog(@"maskOriginPoint.x = %f, maskOriginPoint.y = %f\n",maskOriginPoint.x, maskOriginPoint.y);
//NSLog(@"scaleSize.width = %f, scaleSize.height = %f\n", scaleSize.width, scaleSize.height);
//NSLog(@"screenRealSize.width = %f, screenRealSize.height = %f\n", screenRect.size.width, screenRect.size.height);
//NSLog(@"moveX = %f, moveY = %f\n", deltaX, deltaY);
#endif
// 移出右外
if(deltaX < 0)
{
//NSLog(@"right outside!\n");
rect.origin.x= -(scaleSize.width - screenRect.size.width);
maskOriginPoint.x= scaleSize.width - screenRect.size.width;
}
// 优先右上对齐
// 当x小于零,表示移出左外
if (maskOriginPoint.x < 0)
{
//NSLog(@"left outside!\n");
rect.origin.x= 0;
maskOriginPoint.x= 0;
}
else// x > 0
{
if (rect.size.width < screenRect.size.width)
{
//NSLog(@"up outside!\n");
rect.origin.x= 0;
maskOriginPoint.x= 0;
}
}
// 当y小于零,表示移出上外
if (maskOriginPoint.y < 0 )
{
//NSLog(@"up outside!\n");
rect.origin.y= 0;
maskOriginPoint.y= 0;
}
else// y > 0
{
if (rect.size.height < screenRect.size.height)
{
//NSLog(@"up outside!\n");
rect.origin.y= 0;
maskOriginPoint.y= 0;
}
}
[imageViewsetFrame:rect];
[UIViewcommitAnimations];
//NSLog(@"maskOriginPoint.x = %f", maskOriginPoint.x);
//NSLog(@"animation end: scaleSize.width = %f, scaleSize.height = %f\n", scaleSize.width, scaleSize.height);
}
}
/*
*计算touch的两个点的距离
*/
- (CGFloat)distanceBetweenTwoPoints:(CGPoint)fromPoint toPoint:(CGPoint)toPoint
{
float x = toPoint.x - fromPoint.x;
float y = toPoint.y - fromPoint.y;
returnsqrt(x * x + y * y);
}
/*
*根据移动的距离,计算相应的缩放比例
*/
- (CGFloat)scaleAmount: (CGFloat)delta
{
CGFloat pix = sqrt(self.bounds.size.width * self.bounds.size.height);
CGFloat scale = 1.0 + (delta / pix);
return scale;
}
/*
*释放内存
*/
- (void) dealloc
{
[imageViewrelease];
[originImagerelease];
[superdealloc];
}
@end