前回の目玉商品

[thumbScrollView setCanCancelContentTouches:NO];

 もう、お試しになりましたか?
 デフォルトのYESだと、ずっとUIScrollView側も指の動きを監視し続けるみたいですね。

 なので、こいつをNOで呼んでいないと、UIScrollViewに埋め込んだthumbViewをドラッグしようとしても、ちょっと指を動かしただけでUIScrollView側のフリックジェスチャとかドラッグとして取られてしまい、thumbViewには「オメーの出る幕じゃねえずら」とばかりにtouchesCancelledが飛んでくる・と。虎眼流の「流れ」なみに飛んで、ひつこいですか?そうですか...

 埋め込みUIView側をドラッグ可能にする予定ならsetCanCancelContentTouches:NOを呼んでおけ、ちゅーことですな。
 あと、NOを指定したからといって、まったくUIScrollView側のフリックやドラッグが無効になるというわけじゃなく、ちゃんと機能してくれるんですよね。
 これは「iPhoneアプリ開発、その(121)」で調べたdelaysContentTouchesが効いてるせいだと思われるっす。
 こいつが機能してるとthumbViewにtouchesBeganが届くのはUIScrollView側のフリックやドラッグ判定が終わってからってことになる。
 試しに

[thumbScrollView setCanCancelContentTouches:NO];
thumbScrollView.delaysContentTouches = NO;

 とすると、UIScrollView側のフリックやドラッグがまったくできなく(もちろんthumbView以外の部分をタッチしたなら、ちゃんと機能するけど)なりました。
 ちなみに以前から適当にドット表記を混ぜてますが

thumbScrollView.canCancelContentTouches = NO;
thumbScrollView.delaysContentTouches = NO;

 としても

[thumbScrollView setCanCancelContentTouches:NO];
[thumbScrollView setDelaysContentTouches:NO];

 としても問題ナッシングです。ここらへんは「Objective-C 2.0 プログラミング言語(日本語訳)」読みましょう。

 delaysContentTouches=YESでディレイがあるとthumbViewを押してちょっと待ってから動かさないとthumbViewをドラッグできないんだけど、使ってみると、そんなに不便は感じない。メリットの方が大きいように思えるから、デフォルトYESなんでしょう。私もYESで行きます。

[thumbScrollView setClipsToBounds:NO];

 は、YESにすると下の図のようにUIScrollView外への書き出しを許さなくできるみたい。

テン・シー・シー-1
画像ドラッグ時の見た目だけの問題だけど、だいぶイメージが変わる

 よくわからないのが、Apple'sサンプルソースThumbImageViewクラスのinitWithImageメソッドにある

[self setExclusiveTouch:YES];

 って呼び出し。試しにtouchesMovedメソッドに

printf("touchesMoved %x\n", self);

 とやってみた(selfの値はインスタンス毎に変わるので)んだけど、特に別のビューにtouchesMovedが渡る事はなかった。

[self.nextResponder touchesMoved:touches withEvent:event];

 が必要なのかと加えてみても効果無し。今のところ、なぜ必要なのかわかりません。
 オートスクロールや配置アニメーションのさいに意味があるのかもしれませんな。
 ということで、いよいよデリゲートの追加っす。

@protocol thumbViewDelegate
@optional
- (void)thumbViewStartedTracking:(thumbView *)tiv;
- (void)thumbViewMoved:(thumbView *)tiv;
- (void)thumbViewStoppedTracking:(thumbView *)tiv;
@end

 @optionalってのは、実装が無くても許すって事か?ドキュメント読んでもいまいち不明。
 今回、thumbViewWasTappedは実装しません。
 で、このデリゲートをthumbView側で利用、listViewControllerクラス側に実装するわけですが、ここらへんの過程は「iPhoneアプリ開発、その(120)」を参照してください。
 今回はlistViewControllerクラス側のデリゲート実装の解説。

thumbImageViewStartedTracking
 ドラッグを開始するthumbViewをUIScrollViewに埋め込まれたthumbView群の一番手前に持ってくる。

テン・シー・シー-3

 ま、配置された順でも、それはそれで正しい。ここらへんはアプリケーションの用途によって変わってきますね。

thumbImageViewMoved
 Apple'sサンプルではオートスクロールと、thumbView再配置アニメーションの二つを担当してます。 

[self maybeAutoscrollForThumb:draggingThumb];

 がオートスクロールで、その後の処理はthumbView再配置アニメーションです。
 今回はオートスクロールだけ実装することにします。

maybeAutoscrollForThumb
 ドラッグ中のthumbViewからドラッグ開始点を取り出し、以下のメソッドでthumbView上の座標からthumbScrollView上の座標に変換する。

[thumb convertPoint:[thumb touchLocation] toView:thumbScrollView]

 これが、以下の図のように[thumbScrollView bounds]のAUTOSCROLL_THRESHOLD領域であれば、右、左いずれかの方向にスクロールさせる。

テン・シー・シー-2

 ただし、その場でスクロールするのではなくNSTimer使い、1/60秒間隔でオートスクロールさせる。

[NSTimer scheduledTimerWithTimeInterval:(1.0 / 60.0)
target:self
selector:@selector(autoscrollTimerFired:)
userInfo:thumb
repeats:YES];

1/60秒間隔てselfで指定されたインスタンスのautoscrollTimerFired:メソッドを繰り返し呼び出す。
userInfo:にドラッグ中のthumbViewであるthumbを指定しているのは、autoscrollTimerFiredメソッドでドラッグ中のthumbViewを特定する必要があるため。

 thumbViewのmoveByOffset:メソッドをmaybeAutoscrollForThumbメソッド内で呼び出すと無限ループになっちゃうってのもあるけど、それは実装の仕方でどうとでもなる。たぶん一番の理由は一定間隔でスクロールさせたいからでしょう。CAAnimation使う場合CALayerからいろいろ準備が必要なんで、てっとりばやくNSTimerを使うのか?
 あと、オートスクロール中にユーザーのドラッグでthumbViewがthumbScrollViewのbounds内に入った場合、ただちにオートスクロールをやめるようになってます。それが

[autoscrollTimer invalidate];
autoscrollTimer = nil;

 です。

autoscrollTimerFired
 タイマーで1/60秒ごとに実行され、thumbScrollViewをオートスクロールするメソッド。
 setContentOffsetメソッドを使ってスクロールさせている。
 あと、このままだとドラッグ中のthumbViewも一緒にスクロールしちゃうので

thumbView *thumb = (thumbView *)[timer userInfo];
[thumb moveByOffset:CGPointMake(autoscrollDistance, 0)];

 として、ドラッグ中のthumbViewはその場に残るようにしてます。
 内部で呼びだしてるautoscrollDistanceForProximityToEdgeで使われている

float ceilf(float x);

 は引き数を下回らない最小の整数値を返す関数だそうです。
 例) ceilf(0.5) = 1.0、 ceil(-0.5) = 0.0

 1.2ピクセルとか、2.35ピクセルとかではなく1ピクセル、3ピクセルというような移動にしたいみたい。
 これで、オートスクロールまで実装完了。
 次回の再配置アニメーション実装でサンプルプロジェクトAutoscroll.xcodeprojの解析は、ほぼ完了ですな。

------------
サンプルプロジェクト:sc6.zip