可拖曳設定圖片的物件,可以運用在快捷建設定中,將圖片拖曳至預先設定好的設定區域上(上圖淺灰色方塊部分),設定區域就會將拖曳的圖片設定其中,如果是將圖片拖曳到非設定區域上,被拖曳的圖片則會返回它的起始位置,關於更詳細的示範,可以參考文內的 YouTube 連結。
參考文章
包含一些在實作此示範時,可能會需要使用到文章。
- Class 類別初始化的寫法(建構式)
- 使用 initWithCoder 初始化 Storyboard 上的元件
- 產生可以拖曳物件的方法
- Touch Panel / 觸碰螢幕 / 壓力感應器的基本使用方式
- 取得畫面上所有的元件並判斷它們所屬的類別
- 簡單製作 UIImageView 的旋轉與翻轉動畫
- Core Graphic 的碰撞偵測
物件的介面宣告
首先新增一個繼承於UIImageView 的 Objective-C class -- MLDragingView,並宣告以下介面。
@interface MLDragingView : UIImageView {
CGPoint offsetLocation;
UIImageView *dragView;
}
- (MLDragingView *)initWithCoder:(NSCoder *)c;
@end
其中參數 offsetLocation 是用來輔助物件在拖曳時的位移量計算,而 dragView 則是當被拖曳的物件,這樣做的原意是,我們並不想讓使用者真正去移動 MLDragingView 這個物件,而是當使用者點擊 MLDragingView 物件準備要拖曳時,另外產生一個 dragView 讓使用者去拖曳設定的動作。
在物件初始化的部份則是使用 initWithCoder,讓 MLDragingView 與 storyBoard 上的UIImageView 元件做連結。
物件的實作
初始化
在實作檔的部份,首先是 initWithCoder 初始化方法函式,在方法函式中除了初始化 dragView 之外,還將 dragView 的 tag 設定成 -1,並且將 MLDragingView 設定成可以與使用者做互動(這樣才能觸發與 UITouch 有關的內建函式)。
另外 tag 的設定是為了在取得畫面上所有的 UIImageView 時,分辨是否為設定區域還是非設定區域,這部份的實作稍後就會看到。
- (MLDragingView *)initWithCoder:(NSCoder *)c {
self = [super initWithCoder:c];
if (self) {
dragView = [[UIImageView alloc]init];
[dragView setTag:-1];
[self setUserInteractionEnabled:YES];
}
return self;
}
拖曳
在完成初始化的程式碼之後,接下來我們要來實作與觸碰相關的三個內建方法函式 touchesBegan、touchesMoved 和 touchesEnded。
在 touchesBegan 的部份,除了要記錄當前觸碰的位置以便之後做位移量的換算之外,還要設定 dragView 的圖案內容與位置,然後顯示於畫面上,注意顯示在畫面上的方法函式並非 [self addSubview:] 而是 [[self superview] addSubview:],因為我們是要將 dragView 添加在主畫面上,並非 MLDragingView 上。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
offsetLocation = [[touches anyObject] locationInView:self];
[dragView setImage:self.image];
[dragView setFrame:self.frame];
[[self superview] addSubview:dragView];
}
在 touchesMoved 部分則是實作出 dragView 被拖曳的效果。
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint movePoint = [[touches anyObject] locationInView:self];
CGRect frame = self.frame;
frame.origin.x += movePoint.x - offsetLocation.x;
frame.origin.y += movePoint.y - offsetLocation.y;
[dragView setFrame:frame];
}
在 touchesEnded 的部份,我們使用一個 BOOL 型態的參數來判斷是否有找到符合的設定區域部分,如果有找到符合的 UIImageView ,就將其的圖案內容設定成與 dragView 相同,並將 dragView 移出畫面,如果為否,就呼叫讓 dragView 返回原先位置的動畫。
在判斷是否為設定區域上我們並沒有多做設定,凡是只要符合 UIImageView 類別的元件並且它正與 dragView 有「重疊」,都可以被設定,由於 dragView 也算是 UIImageView 的一員因此特別利用 tag 將其隔開排除在外。
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
BOOL find = NO;
for (UIImageView *view in [[self superview] subviews]) {
if (view.tag != -1 && CGRectIntersectsRect(dragView.frame, view.frame)) {
[view setImage:dragView.image];
[view setBackgroundColor:[UIColor clearColor]];
[dragView removeFromSuperview];
find = YES;
}
}
if (!find) {
[self returnAnimation];
}
}
動畫
最後是讓 dragView 返回原先位置的動畫部分,這是一個我們自行定義的方法函式,除了讓 dragView 返回原先位置外,當動畫結束後,同樣也將 dragView 重畫面上移除。
- (void)returnAnimation {
[UIView beginAnimations:@"Return" context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)];
[dragView setFrame:self.frame];
[UIView commitAnimations];
}
- (void)animationFinished:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
[dragView removeFromSuperview];
}
MLDragingView 物件的使用方法
MLDragingView 在使用上非常容易,由於我們已經對其建立了 initWithCoder 初始化方法函式,因此只要在 Storyboard 上隨意拉幾個 UIImageView 元件,設定好內圖案內容,並且將它們的 Custom Class 改成 MLDragingView 即可。
在本範例中的 4 個 UIImageView 中,只有左手邊的 UIImageView 的 Custom Class 是屬於 MLDragingView,右邊的三個 UIImageView 的 Custom Class 則是維持原樣,因此他們只能「被設定」,而不能拖曳設定其他的 UIIMageView。
YouTube 示範
想再UIImageView 類別的元件並且它正與 dragView 有「重疊」的情況之下,進行跳頁的動作,但是都無法實作出來,不知道是哪一個環節出錯了。
回覆刪除擷取 for迴圈內
------------------------------------------------
testmc *b =[[testmc alloc] initWithNibName:nil bundle:nil];
[UIView transitionFromView:self.superview
toView:b.view
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:^(BOOL finished){
}];
[dragView removeFromSuperview];
find = YES;
------------------------------------------------
這樣似乎可以換到下一頁,但是只要按button都會出現錯誤,真是orz
您好:
刪除按下 button 會出錯,是什麼樣的錯誤?會不會是按鈕與事件沒連結好?
也許你可以先不要試著「換頁」,在程式開始時直接使用你產生的新 UIView,看看能不能正常運作。
請問一下
回覆刪除如果我想動態生成圖片
如何才能設定他的class為MLDragingView?
謝謝~
Frank-wu 您好:
刪除你可以參考這一篇「Class 類別初始化的寫法(建構式)」將初始話的方法寫到裡面即可。
http://furnacedigital.blogspot.tw/2011/02/blog-post_18.html
文內所使用的方法為「使用 initWithCoder 初始化 Storyboard 上的元件」,它是初始化storyboard上固有的物件。
http://furnacedigital.blogspot.tw/2012/04/initwithcoder-storyboard.html