en

hi, it seems you are using microsoft internet explorer. it doesn't match web standard and causes problems browsing this site. please please please use mozilla firefox or google chrome instead. thank you!

zh

哦哦!您正在使用Internet Explorer 瀏覽器,它與我們的網頁標準並不相容,可能會導致畫面顯示不正常。
請改用 Mozilla Firefox 或者 Google Chrome 才能正常瀏覽本網站,謝謝!

1.13.2012

產生可以拖曳物件的方法

 

本篇要示範的是產生一個可以拖曳物件的方法,這個物件在產生時就賦予能被拖曳的功能,並且顯示目前物件所在位置的座標,同時我們也處理物件彼此覆蓋的問題,以及物件的拖曳範圍。下面,我們將從利用 UIView subclass 來這製作個物件開始說起。


物件的初始化
首先新增一個 UIView subclass,你可以從新增 Objective-C class 的項目裡找到 UIView subclass 的類型,並將此 class 命名為 dot。

新增 Objective-C class

接著我們按照需求,在 dot.h 中宣告兩個 Property (UILabel 物件)與一個初始化方法函式,它們將分別顯示目前物件所在位置的 XY 座標,和定義可拖曳物件的初始化步驟。
@property (strong)UILabel *xLabel;
@property (strong)UILabel *yLabel;

- (Dot *)initWithPoint:(CGPoint)point;

並在 dot.m 中 實作初始化方法函式,與兩個物件的存取合成方法 Synthesize。
@synthesize xLabel, yLabel;
- (Dot *)initWithPoint:(CGPoint)point {
    self = [super init];

    if (self) {
        UIImageView *dotImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"dot.png"]];
        CGSize imageSize = dotImageView.frame.size;

        //將畫面大小設成與圖片大小相同
        [self setFrame:CGRectMake(point.x, point.y, imageSize.width, imageSize.height)];
        [self addSubview:dotImageView];

        //設定UILabel
        xLabel = [[UILabel alloc]initWithFrame:CGRectMake(imageSize.width +1, 0.0, 20.0, 15.0)];
        yLabel = [[UILabel alloc]initWithFrame:CGRectMake(imageSize.width +1, 16.0, 20.0, 15.0)];

        UIFont *font = [UIFont fontWithName:@"Arial" size:10.0];
        [xLabel setFont:font];
        [yLabel setFont:font];

        xLabel.text = [NSString stringWithFormat:@"%.f", point.x];
        yLabel.text = [NSString stringWithFormat:@"%.f", point.y];

        [xLabel setBackgroundColor:[UIColor clearColor]];
        [yLabel setBackgroundColor:[UIColor clearColor]];

        [self addSubview:xLabel];
        [self addSubview:yLabel];

        //不切除超過邊界的畫面
        [self setClipsToBounds:NO];
    }

    return self;
}

在上述程式碼中有個小技巧,我們將整個物件的邊界範圍大小設定成與圖片的長寬相同,在此範圍內做點擊都可以觸發物件的拖曳動作,並且將兩個顯示座標的 UILabel 故意放在此範圍之外,表示即使手指觸碰 UILabel 也無法對物件進行拖曳。


物件的拖曳事件
在物件的拖曳事件裡,我們要使用到兩個 UIView 內建的方法函式,touchesBegan 和 touchesMoved,這兩個方法函式分別會在手指觸碰到物件的同時與拖曳物件的同時被觸發,並且我們要在 dot.h 中宣告一個 CGPoint 形態的變數,方便讓我們記錄和取用觸碰畫面的座標。
@interface Dot : UIView {
    CGPoint location;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    //將被觸碰到鍵移動到所有畫面的最上層
    [[self superview] bringSubviewToFront:self];

    CGPoint point = [[touches anyObject] locationInView:self];
    location = point;
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    CGPoint point = [[touches anyObject] locationInView:self];

    CGRect frame = self.frame;

    frame.origin.x += point.x - location.x;
    frame.origin.y += point.y - location.y;
    [self setFrame:frame];

    xLabel.text = [NSString stringWithFormat:@"%.f", frame.origin.x];
    yLabel.text = [NSString stringWithFormat:@"%.f", frame.origin.y];
}

在 touchesBegan 方法函式中,觸碰到物件的同時就會將物件帶往畫面的最上層避免遮蔽,之後將觸碰的座標記錄起來,等到物件被拖曳時,在 touchesMoved 方法函式中,就可以利用此座標重新計算物件的位置,並且反應在兩個 UILAbel 上。


物件的生成
現在,可以拖曳的物件易經完全建立好了,只要在程式中 import dot class,並且呼叫 dot 的初始化方法函式,就可使用此拖曳物件,下面程式碼是在 View Controller 中的按鈕事件裡加入可以拖曳的物件。
#import "Dot.h"
- (IBAction)setDot:(id)sender {

    //物件顯示於畫面中心
    Dot *theDot = [[Dot alloc] initWithPoint:self.view.center];
    [self.view addSubview:theDot];
}

最後,我們物件的定位點並不是在物件的 Center 中心點,而是左上角(預設值),所以上述動作其實是將物件的左上角放置在畫面的中心,如果你想要改變物件的定位點可以參考AnchorPoint 概述ㄧ文, 在建構式中重新設定物件的定位點。


相關文章






4 則留言:

  1. 請問一下,如果要做一個按下去可往上拖曳一段距離,放開才到下一頁的按鈕要怎麼做呢?

    回覆刪除
    回覆
    1. Bard 您好:

      按鈕的部份,它在事件處理上本身就有「按下」與「放開」兩種不同的事件,你可以與 touchesMoved: 等函式互相配合,即可達到您的要求。

      刪除