複数のサブビューを持つビューがあります。ユーザーがサブビューをタップすると、サブビューのサイズが拡大して画面の大部分をカバーしますが、他のサブビューの一部は引き続き下に表示されます。
サブビューの1つがこのように「拡張」されている場合、アプリが他のサブビューへのタッチを無視するようにします。これを達成する簡単な方法はありますか?これを処理するコードを書くことはできますが、もっと簡単な組み込みの方法があることを望んでいました。
複数のサブビューを持つビューがあります。ユーザーがサブビューをタップすると、サブビューのサイズが拡大して画面の大部分をカバーしますが、他のサブビューの一部は引き続き下に表示されます。
サブビューの1つがこのように「拡張」されている場合、アプリが他のサブビューへのタッチを無視するようにします。これを達成する簡単な方法はありますか?これを処理するコードを書くことはできますが、もっと簡単な組み込みの方法があることを望んでいました。
この助けを願っています...
[[yourSuperView subviews]
makeObjectsPerformSelector:@selector(setUserInteractionEnabled:)
withObject:[NSNumber numberWithBool:FALSE]];
これにより、ビューの直接のサブビューのuserInteractionが無効になります。次に、必要な唯一のビューにuserInteractionを指定します。
yourTouchableView.setUserInteraction = TRUE;
iOSでは、親ビューでuserInteractionを無効にしても、その子でuserInteractionが無効にならないようです。したがって、上記のコード(つまり、のコード makeObjectsPerformSelector:
)は、親の直接のサブビューのuserInteractionを無効にする場合にのみ機能します。
すべてのサブビューを再帰的に取得し、それらすべてのユーザー操作を無効にするユーザーmadewulfの回答を参照してください。または、プロジェクトの多くの場所でこのビューのuserInteractionを無効にする必要がある場合は、UIViewを分類して、その機能を追加できます。
@interface UIView (UserInteractionFeatures)
-(void)setRecursiveUserInteraction:(BOOL)value;
@end
@implementation UIView(UserInteractionFeatures)
-(void)setRecursiveUserInteraction:(BOOL)value{
self.userInteractionEnabled = value;
for (UIView *view in [self subviews]) {
[view setRecursiveUserInteraction:value];
}
}
@end
今、あなたは呼び出すことができます
[yourSuperView setRecursiveUserInteraction:NO];
また、すべてのビューの上に非表示のビューを追加するというユーザー@lxtの提案は、それを行うもう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
仕事をします。親ビューは、ビューのすべてのサブビューでのユーザー操作を無効にします。ただし、有効にすると、すべてのサブビューが有効になるわけではありません(デフォルトではUIImageViewは対話可能ではありません)。したがって、簡単な方法は、親ビューを見つけて上記のコードを使用することです。セレクターを実行するためにすべてのサブビューを繰り返す必要はありません。
TapGestureRecognizerを「背景ビュー」(通常のインターフェースを「グレー表示」する半透明のビュー)に追加し、アクションを追加せずに「ビュー内のタッチをキャンセル」に設定します。
let captureTaps = UITapGestureRecognizer()
captureTaps.cancelsTouchesInView = true
dimmedOverlay?.addGestureRecognizer(captureTaps)
私はこの問題に私の2セントを与えます。userInteractionEnabled=falseを繰り返し実行します。これは一方向です。別の方法は、次のような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;
これがお役に立てば幸いです。
setUserInteractionEnabled = NO
無効にするビューで
私のアプリの場合、アプリの他のタブへのナビゲーションを無効にするだけで十分だと思います(処理を行っている間、限られた時間だけ):
self.tabBarController.view.userInteractionEnabled = NO;
また、現在のViewControllerを無効にしました--
self.view.userInteractionEnabled = NO;
(ちなみに、ここで提案された再帰的ソリューションは、私のアプリで奇妙な効果をもたらしました。無効化は正常に機能しているようですが、再有効化には奇妙な効果があります。一部のUIは再度有効化されませんでした)。
シンプルなソリューション。何もしないダミージェスチャを追加します。次のような拡張機能に追加して、再利用可能にします。
extension UIView {
func addNullGesture() {
let gesture = UITapGestureRecognizer(target: self,
action: #selector(nullGesture))
addGestureRecognizer(gesture)
}
@objc private func nullGesture() {}
}
私は同じ問題を抱えていましたが、上記の解決策は役に立ちませんでした。super.touchesBegan(...)
それから私は電話が問題であることに気づき
ました。これを削除した後、イベントは最上位のビューによってのみ処理されました。
これが誰かの助けになることを願っています。