4

UIScrollViewサブクラスを実装して、カスタム形式のコンテンツを表示したいと考えています。スクロール ビューのモデル オブジェクト プロパティを設定するだけで、コンテンツを表示するために必要なすべてのレイアウトとレンダリングが処理されます。

これで問題なく動作しますが、ズームを含めたいと思います。ドキュメントによると、ズームをサポートするには、デリゲートを設定してviewForZoomingInScrollView:メソッドを実装する必要があります。デリゲートをスクロール ビュー自体に設定し、そのメソッドをサブクラスに実装できると思います。しかし、それを行うと、スクロール イベントについて通知できる外部デリゲート (カプセル化された UIViewController など) を持つことができなくなります。

ドキュメントが正しく、デリゲートなしでズームを実装する (ドキュメント化された) 方法がまったくないと仮定すると、通常の無関係なデリゲートを持つ可能性を保持するにはどうすればよいでしょうか?

4

3 に答える 3

5

本物のデリゲートへの隠しポインターを保存し、すべての着信メッセージをそこに転送するという H2CO3 の提案に基づいて、私は次の解決策を思いつきました。

setDelegate:メソッドに渡される「実際の」デリゲートへの参照を格納するプライベート デリゲート変数を宣言します。

@interface BFWaveScrollView ()
@property (nonatomic, weak) id<UIScrollViewDelegate> ownDelegate;
@end

デリゲートを self に設定して、スクロール イベントについて通知を受けます。を使用superして、元のsetDelegate:実装が呼び出され、変更されたものではありません。

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [super setDelegate:self];
    }
    return self;
}

setDelegate:「実際の」デリゲートへの参照を保存するためにオーバーライドします。

- (void)setDelegate:(id<UIScrollViewDelegate>)delegate {
    _ownDelegate = delegate;
}

UIScrollViewがデリゲートのメソッドを呼び出そうとすると、最初にデリゲートかどうかがチェックされますrespondsToSelector:。セレクターがプロトコルの一部である場合は、これを実際のデリゲートに転送する必要がありUIScrollViewDelegateます (忘れないでください#import <objc/runtime.h>)。

- (BOOL)selectorIsScrollViewDelegateMethod:(SEL)selector {
    Protocol *protocol = objc_getProtocol("UIScrollViewDelegate");
    struct objc_method_description description = protocol_getMethodDescription(
                                                   protocol, selector, NO, YES);
    return (description.name != NULL);
}

- (BOOL)respondsToSelector:(SEL)selector {
    if ([self selectorIsScrollViewDelegateMethod:selector]) {
        return [_ownDelegate respondsToSelector:selector] ||
               [super respondsToSelector:selector];
    }
    return [super respondsToSelector:selector];
}

最後に、サブクラスに実装されていないすべてのデリゲート メソッドを実際のデリゲートに転送します。

- (id)forwardingTargetForSelector:(SEL)selector {
    if ([self selectorIsScrollViewDelegateMethod:selector]) {
        return _ownDelegate;
    }
    return [super forwardingTargetForSelector:selector];
}

サブクラスによって実装されるデリゲート メソッドを手動で転送することを忘れないでください。

于 2013-03-27T23:15:38.387 に答える
2

私はサブクラスであるという事実を悪用します(意図的に:P)。だからあなたはそれをハックすることができます。本当に悪いことです。この解決策を提案するのは悪いことです。

@interface MyHackishScrollView: UIScrollView {
    id <UIScrollViewDelegate> ownDelegate;
}

@end

@implementation MyHackishScrollView

- (void)setDelegate:(id <UIScrollViewDelegate>)newDel
{
    ownDelegate = newDel;
    [super setDelegate:self];
}

- (UIView *)viewForScrollingInScrollView:(UIScrollView *)sv
{
    return whateverYouWant;
}

// and then implement all the delegate methods
// something like this:
- (void)scrollViewDidScroll:(UIScrollView *)sv
{
    [ownDelegate scrollViewDidScroll:self];
}

// etc.

@end
于 2013-03-27T22:20:29.537 に答える