複数のサブビューを持つビューがあります。ユーザーがサブビューをタップすると、サブビューのサイズが拡大して画面の大部分をカバーしますが、他のサブビューの一部はまだ下に表示されます。
サブビューの1つがこのように「展開」されている場合、他のサブビューへのタッチをアプリで無視するようにします。これを達成する簡単な方法はありますか?これを処理するコードを書くことはできますが、もっと簡単な組み込みの方法があることを望んでいました。
これを行うにはいくつかの方法があります。他のすべてのサブビューを反復処理して、userInteractionEnabled = NO
、しかし、これは他のビューがたくさんある場合には理想的ではありません(結局、それらをすべてレンディングする必要があります)。
これを行う方法は、すべてのタッチが他のビューに移動するのを「ブロック」する、画面全体のサイズである非表示のUIViewを作成することです。これは文字通り目に見えないこともあれば、0.3程度のアルファ値で黒に設定することもあります。
メインサブビューを展開して画面いっぱいに表示するときに、この「ブロック」UIViewをその背後に追加できます(insertSubview: belowSubview:
)。展開したサブビューを最小化すると、非表示のUIViewを階層から削除できます。
組み込みではありませんが、最も簡単なアプローチだと思います。それがすでにあなたが考えていたものであるかどうかはわかりませんが、うまくいけばそれは何らかの助けになるでしょう。
Krishnabhadraが解決策としてここに示したコードに注意してください。
[[yourSuperView subviews]makeObjectsPerformSelector:@selector(setUserInteractionEnabled:) withObject:[NSNumber numberWithBool:FALSE]];
[yourSuperView subviews]はスーパービューの直接のサブビューのみを提供するため、これはすべてのケースで機能するわけではありません。動作させるには、すべてのサブビューで再帰的に反復する必要があります。
-(void) disableRecursivelyAllSubviews:(UIView *) theView
{
theView.userInteractionEnabled = NO;
for(UIView* subview in [theView subviews])
{
[self disableRecursivelyAllSubviews:subview];
}
}
-(void) disableAllSubviewsOf:(UIView *) theView
{
for(UIView* subview in [theView subviews])
{
[self disableRecursivelyAllSubviews:subview];
}
}
これで、disableAllSubviewsOf
への呼び出しは、あなたがやりたいことをするでしょう。
ビューのスタックが深い場合は、lxtによる解決策がおそらく優れています。
これを行うには、superView
と同じフレームにカスタム透明ボタンを配置します。そして、そのボタンの上に、ユーザーのタッチを受け入れるビューを配置します。 ボタンはすべてのタッチを飲み込みますで、その背後のビューはタッチイベントを受信しませんが、ボタンの上部のビューは通常のタッチを受信します。
このようなもの:
- (void)disableTouchesOnView:(UIView *)view {
UIButton *ghostButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, view.frame.size.width, view.frame.size.height)];
[ghostButton setBackgroundColor:[UIColor clearColor]];
ghostButton.tag = 42; // Any random number. Use #define to avoid putting numbers in code.
[view addSubview:ghostButton];
}
parentView
を有効にする方法。
- (void)enableTouchesOnView:(UIView *)view {
[[view viewWithTag:42] removeFromSuperview];
}
したがって、parentViev
の背後にあるyourView
のすべてのビューを無効にするには、次のようにします。
YourView *yourView = [[YourView alloc] initWithCustomInitializer];
// It is important to disable touches on the parent view before adding the top most view.
[self disableTouchesOnView:parentView];
[parentView addSubview:yourView];
ただparentView.UserInteractionEnabled = NO
が作業を行います。親ビューはdisableすべてのビューのサブビューでのユーザーインタラクションになります。しかし、enableそれはenableすべてのサブビューではありません(デフォルトではUIImageViewは相互作用しません)。したがって、簡単な方法は親ビューを見つけて上記のコードを使用することです。セレクターを実行するためにすべてのサブビューを繰り返す必要はありません。
この問題に2セントを割り当てます。 userInteractionEnabled = falseを繰り返し実行します。これは1つの方法です。別の方法は、次のようなUIViewを追加することです。
EZEventEater.h
#import <UIKit/UIKit.h>
@interface EZEventEater : UIView
@end
EZEventEater.m
#import "EZEventEater.h"
@implementation EZEventEater
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
self.userInteractionEnabled = false;
}
return self;
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//EZDEBUG(@"eater touched");
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
コードにEZEventEaterビューを追加して、タッチイベントをブロックする可能性のあるすべてのビューをカバーします。これらのビューへのタッチイベントをブロックする場合は、いつでも呼び出します
eater.userInteractionEnabled = YES;
これが役に立てば幸いです。
TapGestureRecognizerを "バックグラウンドビュー"(通常のインターフェイスを "グレー表示"する半透明のビュー)に追加し、アクションを追加せずに "Cancels Touches In View"に設定します。
let captureTaps = UITapGestureRecognizer()
captureTaps.cancelsTouchesInView = true
dimmedOverlay?.addGestureRecognizer(captureTaps)
私のアプリの場合、アプリの他のタブへのナビゲーションを無効にすれば十分だと思います(処理を行っている間、限られた期間):
self.tabBarController.view.userInteractionEnabled = NO;
また、現在のView Controllerを無効にしました
self.view.userInteractionEnabled = NO;
(ちなみに、ここで提案した再帰的な解決策は私のアプリに奇妙な効果をもたらしました。無効化はうまく機能しているようですが、再有効化には奇妙な効果があります。
setUserInteractionEnabled = NO
無効にするビューで