No.7ベストアンサー
- 回答日時:
> 私が思い当ったコードは
> CGPoint pt = [[touches anyObject] locationInView:self.superview];
> self.center = pt;
> で、タッチした際UIImageViewが少し下にずれるようなことがたまにあったので他によい方法はないのか
それは、タッチした場所と、Viewのセンター位置の差分を、調節しないと、そういうことになるでしょうね。いい方を変えると、調節すれば、なんの問題もありませんね。いちいち他人にアドバイスを仰ぐようなことではないと思います。
私だったら、どういうコードを書くかということですが、私はUITouchではなく、UIPanGestureRecognizerを使います。
ジェスチャーのStateが「UIGestureRecognizerStateBegan」(画面をタッチして、移動を始めた瞬間)のときに、「setTranslation:inView:」でViewのcenterを登録し、ジェスチャーのState「UIGestureRecognizerStateChanged」(タッチを移動している間」、「translationInView:」で取得されるCGPointに、Viewのcenterをセットしてやると、Viewがぴったり指に追従します。
UITouchを使うケースで、もうすこしアドバイスすることが残っているとしたら、ひとつは「previousLocationInView:」というメソッドを活用することです。
「touchesMoved:withEvent:」メソッドは、タッチを移動しているあいだ、なんども繰り返して呼び出されると、前に説明しましたが、前回呼び出し時のタッチ位置が「previousLocationInView:」で取得できるので、タッチ移動量を計算することが可能になります。
サンプルコード:
記述場所:UIViewControllerのサブクラス
targetObj:指で動かすオブジェクト。UIViewのサブクラス。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
~ // タッチ開始時の処理
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([touch.view isEqual: targetObj]) { // targetObjをタッチしたのなら
CGPoint pt = targetObj.center;
CGPoint prevPt = [touch previousLocationInView: self.view];
CGPoint newPt = [touch locationInView: self.view];
float gapX = newPt.x - prevPt.x; // タッチ移動量を計算
float gapY = newPt.y - prevPt.y;
targetObj.center = CGPointMake(pt.x + gapX, pt.y + gapY);
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
~ // タッチ終了時の処理
}
タッチイベントを処理するメソッドを、UIViewController(のサブクラス)に記述している点に注目してください。それがもうひとつのアドバイスです。UIViewControllerは、UIResponderを継承しているので、タッチイベントの処理が可能です。
「レスポンダチェーン」(Responder Chain)という言葉を覚えてください。いかにもオブジェクト指向的なメカニズムです。
画面を指でタッチすると、タッチイベントが発生しますが、タッチした場所にあるViewがまずタッチイベントを受け取ります。もしそのViewにタッチイベントの処理が用意されていなかったら、そのViewはイベントをSuperviewに譲り渡します。Superviewにイベント処理が用意されていたら、代わって処理を行いますが、SuperviewはみずからのSuperviewにタッチイベントを譲り渡します。このようにイベントは次々にView間を渡っていき、UIWindowに渡され、最終的にUIApplicationに渡されます。どこでもイベントに対する処理がなければ、けっきょくなにも起きずにイベントは消滅します。このイベント受け渡しの経路をレスポンダチェーンと呼びます。経路にあるUIResponderサブクラスなら、プログラム上つごうのいい場所で、イベント処理を記述することができます。
Viewがコントローラ(UIViewController)を持っている場合、タッチイベントは、Superviewに渡される前に、コントローラに渡されます。サンプルコードはこの受け渡しの規則を利用して、UIViewControllerのサブクラスにタッチイベントの処理を記述しています。
タッチイベントを最初に受け取ったViewは、UITouchのプロパティ「view」で取得することができます。
詳しい説明ありがとうございます
最初の質問から主旨少しズレてしまいすみませんでした
それでも最後までつきあっていただき感謝します
次はUIPanGestureRecognizerで作成をしてみようと思います
たびたび質問して来ると思いますが機会があればまたよろしくお願いします
No.6
- 回答日時:
> これでよろしかったでしょうか?
あなたの書いたプログラム全体を把握できないので、その質問には答えられません。しかし、その書き換えであなたの意図どおりの動作になったのなら、正しいと判断していいのではありませんか?
いちど、そのプログラムから離れて、1週間ほど忘れてしまうことです。そのあと、そのプログラムを読み返せば、客観的な判断ができるようになるでしょう。人間は本質とその構造として、進歩し成長するようになっている。人間は自分自身を客観的に把握する能力を有する。このふたつのことを信じる価値があります。
この回答への補足
そうですね。
できればharawoさんが考えたコードをお聞きしたくて
よろしかったですか?と尋ねました
私が思い当ったコードは
CGPoint pt = [[touches anyObject] locationInView:self.superview];
self.center = pt;
で、タッチした際UIImageViewが少し下にずれるようなことがたまにあったので他によい方法はないのか
harawoさんならどのように書くかというのが知りたくて捕捉させていただきました
No.5
- 回答日時:
> このようにしたところ当然UIImageは動きませんがマウスでAのUIButtonの位置まで持っていくと LogにINと表示されました
> 原因は下から3行目と4行目の箇所ですがなぜいけないのか
> どうすればいいのか、というのが分かりません
「UIImage」は動きませんよ。UIViewのサブクラスではありませんからね。UIImageは、オフスクリーンバッファという考え方をクラス化したものです。プログラムが動くたび、画面を書き換えていると、人間の目にはちらつきに見えて、不快になったり疲れさせたりするので、画面表示データと、プログラムの対象のイメージデータを別にし、ある程度書き換えが完了したら、一気に画面表示データと置き換えるというテクニックで使われます。
あなたがいいたいのは「UIImageView」ですね?かんたんにUIImageを画面表示させるための、UIViewのサブクラスです。UIImageとUIImageViewを、意図して書き分けできずに、混同してしまうのは、UIKitというフレームワークを、理解できていないからにほかならないでしょう。
UIViewサブクラスの位置は「マウス」では動かせませんよね?iOSシミュレータ上では、たしかにマウスで動かしますが、実機では指のタッチで動かしますよね?さきほど「ドラッグ」という言葉の使い方を例にとって、GUIを意識したプログラムをするようアドバイスしたつもりなのですが、こちらの意図を理解していたら、こういう混同もしないのでしょうに。
UIViewの位置情報は、「center」という、読み書きのできる便利なプロパティが用意されているのですから、「uiviewsubclass.frame.origin.x」などと、いちいち記述せずに、centerを使いましょう。
UIViewサブクラスのインスタンスuiviewsubclassの位置を、CGPoint「distance」の分だけ動かすには、こう書きます。
uiviewsubclass.center = CGPointMake(uiviewsubclass.center.x + distance.x, uiviewsubclass.center.y + distance.y);
さて、本題の質問に対してですが、取得する座標の基準、メソッド「locationInView:」の引数となるViewは、「self」で正しいんですか?私は違うと思いますが?
この回答への補足
間違った語句が多くてすみません
touchesMoved内を
CGPoint pt = [[touches anyObject] locationInView:self.superview];
self.center = pt;
このように変えたらUIImageViewを動かすことができした。
これでよろしかったでしょうか?
No.4
- 回答日時:
> touchesBegan:にコードは書き込みました
touchesBegan:withEvent:メソッドは、指を画面にタッチした瞬間に、1回だけ呼ばれます。タッチした指を、画面から離さずに移動する間の処理は、「touchesMoved:withEvent:」メソッドに記述します。ここにNSLog()を書くと、指を動かしている間、連続して繰り返しこのメソッドが呼ばれることがわかります。
タッチイベントのメソッドは、「touchesBegan:withEvent:」「touchesMoved:withEvent:」「touchesEnded:withEvent:」「touchesCancelled:withEvent:」の4つがセットと考え、処理を行ってください。ひとつだけ取り出して処理しても、期待どおりにならないことのほうが多いでしょう。ちなみに、touchesCancelled:withEvent:メソッドは、iPhoneで途中電話がかかってきたなど、外的要因でタッチイベントが中断されたときに呼び出されます。
> if (CGRectContainsPoint(A.frame, pt)){
> NSLog(@"TEST");
> }
> と書き込んでみましたが表示されませんでした
条件に一致しないときも、なにかしら出力しなければ、ちゃんと判断できませんよ。
if (CGRectContainsPoint(A.frame, pt)){
NSLog(@"IN");
} else {
NSLog(@"OUT");
}
この回答への補足
原因が判明しました
elseも書き行ったところtouchesMoved内のに問題があることが判明しました(少し長くなりますが)
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
startLocation = [[touches anyObject] locationInView:self];
[[self superview] bringSubviewToFront:self];
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
CGPoint pt = [[touches anyObject] locationInView:self];
CGRect frame = [self frame];
if (CGRectContainsPoint(A.frame, pt)){
NSLog(@"IN");
}else{
NSLog(@"OUT");;
}
//frame.origin.x += pt.x - startLocation.x;
// frame.origin.y += pt.y - startLocation.y;
[self setFrame:frame];
}
このようにしたところ当然UIImageは動きませんがマウスでAのUIButtonの位置まで持っていくと LogにINと表示されました
原因は下から3行目と4行目の箇所ですがなぜいけないのか
どうすればいいのか、というのが分かりません
できればもう少しアドバイスをいただきたいです
No.3
- 回答日時:
> ドラッグのclassに
> CGPoint pt = [[touches anyObject] locationInView:self];
> CGRect frame = [self frame];
> if (CGRectContainsPoint(A.frame, pt)){
> [処理];
> }
> とやってみたのですが処理は実行されませんでした
「なにを」は書かれていても、「どこに」(メソッド)が書かれていないので、なんともコメントのしようがありません。
処理のコードを書いていても、それを呼び出すイベントが発生しなければ、また発生したイベントを、メソッドが受け取らなければ、処理は実行されません。
イベントが発生しているか、あるいは発生したイベントを、メソッドが受け取っているかを調べるには、NSLog()を使った、簡易デバッグが有効でしょう。
そして、冷静に、客観的にプロジェクトを観察すれば、タッチイベントがどのオブジェクト(UIResponderのサブクラス)で受け止められているか、調べるのは容易なはずです。いちど自分のプロジェクトを俯瞰してみてはいかがですか?
(まさか、「touchesMoved:withEvent:」メソッドに書いていないなんてことはありませんよね?)
※「ドラッグ」という言葉は、厳密な定義に従えば、マウスボタンを押したままの状態で、マウスを動かす行為を指します。iPhoneのようなタッチパネル式のインターフェイスでは、使うべき用語とはいえません。Appleの用語では、Touch Moveや、Pan(UIPanGestureRecognizer)が使われます。
この回答への補足
説明が足りませんでしたね
(ドラッグの件も気をつけます)
touchesBegan:にコードは書き込みました
NSLog(@"TEST");とtouchesBegan:の処理内に書き込んだところ表示はされたのでこちらは問題ないのですが
if (CGRectContainsPoint(A.frame, pt)){
NSLog(@"TEST");
}
と書き込んでみましたが表示されませんでした
発生自体はしているはずなのですがメソッドが受け取ってくれていないのだと思います。
TouchMoveの処理がDragView.hに
通過させたいUIButtonの処理がMainViewController.hに書かれているのでController.h内のIBOutlet UIButtonがしっかり認識されてないのが原因でしょうか?
No.2
- 回答日時:
> どういったクラス?を使用すればよいのかなどのアドバイスをいただきたいですね
「UIButtonの画像付きボタンをドラッグ」するのに、UITouchクラスか、UIGestureRecognizerクラスを利用していると思いますが、それらどちらかのメソッドで処理するのが、自然な流れではないでしょうか?
参考:
bool CGRectContainsPoint (
CGRect rect,
CGPoint point
);
ある座標(タッチしているポイント)が、ViewなどのCGRectの内側にあるのか、調べるC言語の関数です。これで判別できます。
> (ちなみにプログラムのサンプルを書いてもらうにはおいくらですか?)
公共の掲示板を使って、営利行為をしたら、まずいですよ。冗談でその質問をなさっているのだと思いますが、こちらの言葉も本気で「金をくれ」といっているのではないことを、誤解しないでください。
この回答への補足
DragView.mを作成しドラッグ用のUIButtonを作成し
MainViewController.mにAというUIButtonを作成
ドラッグのclassに
CGPoint pt = [[touches anyObject] locationInView:self];
CGRect frame = [self frame];
if (CGRectContainsPoint(A.frame, pt)){
[処理];
}
とやってみたのですが処理は実行されませんでした
.hを読み込ませたり、DragView.hにもUIButtonのAを作成してInterfaceBuilderでコネクトさせてみたりといろいろやってみましたがうまくいきませんでした。
(上記のコードだけでは決定的な原因がわかりづらいですね)
できればもう少しアドバイスをお願いしたいです
>誤解しないでください
こちらも冗談のつもりで()を付けて書いたので気にしないでください
No.1
- 回答日時:
Yes or Noの二択回答を求めていらっしゃるなら、回答は「Yes」です。
もし、具体的にそういうプログラムを書いてくれという要求でしたら、お答えしません。(お金がもらえるなら、いくらでもプログラムを書きますけどね。)
ヒントなり、方向性をアドバイスして欲しいということでしょうか?
この回答への補足
返答ありがとうございます
そうですね
どういったクラス?を使用すればよいのかなどのアドバイスをいただきたいですね
教えていただけたらこちらでも調べますし、うまくいかない点があったらまた新しく質問を投稿させてもらいます
(ちなみにプログラムのサンプルを書いてもらうにはおいくらですか?)
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・ちょっと先の未来クイズ第4問
- ・【大喜利】【投稿~10/21(月)】買ったばかりの自転車を分解してひと言
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・ハマっている「お菓子」を教えて!
- ・最近、いつ泣きましたか?
- ・夏が終わったと感じる瞬間って、どんな時?
- ・10秒目をつむったら…
- ・人生のプチ美学を教えてください!!
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ExcelVBA で文字列の特定の文字...
-
C#で別スレッドの終了を知りたい
-
switch文の中に、throws new Ex...
-
エクセルVBAで、条件に一致する...
-
Javaの関数名が長い?
-
河合塾のクラス分けについて
-
同じパッケージ、クラス名が含...
-
VB6のツールボックスへのコンポ...
-
エクセルVBA 画像を貼り付ける...
-
VBAでの[]
-
ゲッターを使わないで変数にア...
-
ビジュアルC++でボタンの有...
-
「インスタンス」の意味をわか...
-
[Visual C#] 優先される処理に...
-
System.load() と System.loa...
-
Visual Studioでのbmpファイル...
-
同じクラスにならない確率を教...
-
委譲って何ですか?
-
onClickで関数呼出し後に、結果...
-
Unity,C#、複数の子オブジェク...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
tryの終了
-
Javaでのデバッグコード削除
-
Tomcat高負荷時の設定について
-
JavaでVBのDOEVENTSと同様の処...
-
[Java] while(true)の意味
-
ExcelVBA で文字列の特定の文字...
-
JavaScriptからJAVAクラスを呼...
-
アコーディオンメニューをアン...
-
SwingUtilities.invokeLater(ne...
-
重い処理を行っているとGIFアニ...
-
ftp 同時複数接続の負荷テスト...
-
数値の定数を付ける時
-
ラベルの表示までが異常に遅い...
-
特定のforwardパス以外をはじき...
-
C#で別スレッドの終了を知りたい
-
JDBCでテーブルUPDATE後の再検...
-
WPF C#でF10のイベント取得方法...
-
doGetとdoPostの違い
-
Mac上でWindowsのファイルパス...
-
PHPでDB処理中にプログレスバー...
おすすめ情報