From 7a0a3b250c5122d6f563331e628fda9ca1c5ef0f Mon Sep 17 00:00:00 2001 From: Igor Pozdeev Date: Wed, 5 Sep 2018 15:25:51 +0400 Subject: [PATCH] * Fix: issue #2 Can't click on Anything + iOS clear button toggle --- Unity/Assets/Plugins/iOS/MobileInput.mm | 58 +- .../Scripts/UnityMobileInput/MobileInput.cs | 536 ++++++++++-------- 2 files changed, 343 insertions(+), 251 deletions(-) diff --git a/Unity/Assets/Plugins/iOS/MobileInput.mm b/Unity/Assets/Plugins/iOS/MobileInput.mm index 4acb1d9..b3e5434 100644 --- a/Unity/Assets/Plugins/iOS/MobileInput.mm +++ b/Unity/Assets/Plugins/iOS/MobileInput.mm @@ -15,6 +15,8 @@ #define SET_TEXT @"SET_TEXT" #define GET_TEXT @"GET_TEXT" #define SET_RECT @"SET_RECT" +#define ON_FOCUS @"ON_FOCUS" +#define ON_UNFOCUS @"ON_UNFOCUS" #define SET_FOCUS @"SET_FOCUS" #define SET_VISIBLE @"SET_VISIBLE" #define TEXT_CHANGE @"TEXT_CHANGE" @@ -192,6 +194,19 @@ -(void) tapAction:(id)sender{ } } +-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event +{ + // Allow buttons to receive press events. All other views will get ignored + for( id foundView in self.subviews ) + { + if( [foundView isKindOfClass:[MobileInput class]] ) + { + return YES; + } + } + return NO; +} + -(void) setObserverForOrientationChanging { [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]]; @@ -238,10 +253,6 @@ @implementation MobileInput +(void) init:(UIViewController *)viewController { unityViewController = viewController; mapMobileInput = [[NSMutableDictionary alloc] init]; - CGRect frameView = unityViewController.view.frame; - frameView.origin = CGPointMake(0.0f, 0.0f); - viewPlugin = [[MobileInputHoldView alloc] initHoldView:frameView]; - [unityViewController.view addSubview:viewPlugin]; } +(void) processMessage:(int)inputId data:(NSString *)data { @@ -321,6 +332,8 @@ -(void) setRect:(NSDictionary *)data { editView.frame = CGRectMake(x, y, width, height); } +BOOL multiline; + -(void) create:(NSDictionary *)data { NSString *placeholder = [data valueForKey:@"placeholder"]; NSString *font = [data valueForKey:@"font"]; @@ -352,7 +365,8 @@ -(void) create:(NSDictionary *)data { NSString *contentType = [data valueForKey:@"content_type"]; NSString *alignment = [data valueForKey:@"align"]; BOOL withDoneButton = [[data valueForKey:@"with_done_button"] boolValue]; - BOOL multiline = [[data valueForKey:@"multiline"] boolValue]; + BOOL withClearButton = [[data valueForKey:@"with_clear_button"] boolValue]; + multiline = [[data valueForKey:@"multiline"] boolValue]; BOOL autoCorr = NO; BOOL password = NO; @@ -494,17 +508,22 @@ -(void) create:(NSDictionary *)data { textField.contentVerticalAlignment = valign; textField.contentHorizontalAlignment = halign; textField.textAlignment = textAlign; + if (withClearButton) + textField.clearButtonMode = UITextFieldViewModeWhileEditing; textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:placeholder attributes:@{NSForegroundColorAttributeName: placeHolderColor}]; textField.delegate = self; if (keyType == UIKeyboardTypeEmailAddress) textField.autocapitalizationType = UITextAutocapitalizationTypeNone; [textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; + [textField addTarget:self action:@selector(textFieldActive:) forControlEvents:UIControlEventEditingDidBegin]; + [textField addTarget:self action:@selector(textFieldInActive:) forControlEvents:UIControlEventEditingDidEnd]; [textField setSecureTextEntry:password]; if (keyboardDoneButtonView != nil) textField.inputAccessoryView = keyboardDoneButtonView; editView = textField; } - [viewPlugin addSubview:editView]; + [unityViewController.view addSubview:editView]; + NSMutableDictionary *msg = [[NSMutableDictionary alloc] init]; [msg setValue:READY forKey:@"msg"]; [self sendData:msg]; @@ -533,7 +552,6 @@ -(int) getLineCount { return 0; } - -(void) remove { [[NSNotificationCenter defaultCenter] removeObserver:self]; [editView resignFirstResponder]; @@ -578,7 +596,21 @@ -(void) textViewDidChange:(UITextView *)textView { [self onTextChange:textView.text]; } +- (void) textViewDidBeginEditing:(UITextView *)textView +{ + if (multiline) { + NSMutableDictionary *msg = [[NSMutableDictionary alloc] init]; + [msg setValue:ON_FOCUS forKey:@"msg"]; + [self sendData:msg]; + } +} + -(void) textViewDidEndEditing:(UITextView *)textView { + if (multiline) { + NSMutableDictionary *msg = [[NSMutableDictionary alloc] init]; + [msg setValue:ON_UNFOCUS forKey:@"msg"]; + [self sendData:msg]; + } [self onTextEditEnd:textView.text]; } @@ -602,6 +634,18 @@ - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRang return YES; } +-(void) textFieldActive:(UITextField *)theTextField { + NSMutableDictionary *msg = [[NSMutableDictionary alloc] init]; + [msg setValue:ON_FOCUS forKey:@"msg"]; + [self sendData:msg]; +} + +-(void) textFieldInActive:(UITextField *)theTextField { + NSMutableDictionary *msg = [[NSMutableDictionary alloc] init]; + [msg setValue:ON_UNFOCUS forKey:@"msg"]; + [self sendData:msg]; +} + -(void) textFieldDidChange:(UITextField *)theTextField { [self onTextChange:theTextField.text]; } diff --git a/Unity/Assets/Scripts/UnityMobileInput/MobileInput.cs b/Unity/Assets/Scripts/UnityMobileInput/MobileInput.cs index 88e3dee..a5e2614 100644 --- a/Unity/Assets/Scripts/UnityMobileInput/MobileInput.cs +++ b/Unity/Assets/Scripts/UnityMobileInput/MobileInput.cs @@ -9,225 +9,256 @@ using UnityEngine; using UnityEngine.UI; -namespace Mopsicus.Plugins.MobileInput { - - /// - /// Wrapper for Unity InputField - /// Add this component on your InputField - /// - [RequireComponent (typeof (InputField))] - public class MobileInput : MobileInputReceiver { - - /// - /// Config structure - /// - private struct MobileInputConfig { - public bool Multiline; - public Color TextColor; - public Color BackgroundColor; - public string ContentType; - public string Font; - public float FontSize; - public string Align; - public string Placeholder; - public Color PlaceholderColor; - public int CharacterLimit; - - } - - /// - /// Button type - /// - public enum ReturnKeyType { - Default, - Next, - Done, - Search - } - - /// - /// Input type - /// - public enum InputType { - AutoCorrect, - Password - } - - /// - /// Keyboard type - /// - public enum KeyboardType { - ASCIICapable, - NumbersAndPunctuation, - URL, - NumberPad, - PhonePad, - NamePhonePad, - EmailAddress - } - - /// - /// "Done" button visible (for iOS) - /// - public bool IsWithDoneButton = true; - /// - /// button type - /// - public ReturnKeyType ReturnKey; - /// - /// input type - /// - public InputType Type; - /// - /// keyboard type - /// - public KeyboardType Keyboard; - /// - /// action when Return pressed - /// - public event Action ReturnPressed; - /// - /// event when Return pressed - /// - public UnityEngine.Events.UnityEvent OnReturnPressed; - /// - /// mobile input creation flag - /// - private bool _isMobileInputCreated = false; - /// - /// InputField object - /// - private InputField _inputObject; - /// - /// Text object from _inputObject - /// - private Text _inputObjectText; - /// - /// set focus on create - /// - private bool _isFocusOnCreate; - /// - /// set visible on create - /// - private bool _isVisibleOnCreate = true; - /// - /// last inputfield position - /// - private Rect _lastRect; - /// - /// config - /// - private MobileInputConfig _config; - - // event for plugin communication - - private const string CREATE = "CREATE_EDIT"; - private const string REMOVE = "REMOVE_EDIT"; - private const string SET_TEXT = "SET_TEXT"; - private const string SET_RECT = "SET_RECT"; - private const string SET_FOCUS = "SET_FOCUS"; - private const string SET_VISIBLE = "SET_VISIBLE"; - private const string TEXT_CHANGE = "TEXT_CHANGE"; - private const string TEXT_END_EDIT = "TEXT_END_EDIT"; - private const string ANDROID_KEY_DOWN = "ANDROID_KEY_DOWN"; - private const string RETURN_PRESSED = "RETURN_PRESSED"; - private const string READY = "READY"; - - /// - /// Constructor - /// - private void Awake () { - _inputObject = this.GetComponent (); - if (_inputObject == null) { +namespace Mopsicus.Plugins.MobileInput +{ + + /// + /// Wrapper for Unity InputField + /// Add this component on your InputField + /// + [RequireComponent(typeof(InputField))] + public class MobileInput : MobileInputReceiver + { + + /// + /// Config structure + /// + private struct MobileInputConfig + { + public bool Multiline; + public Color TextColor; + public Color BackgroundColor; + public string ContentType; + public string Font; + public float FontSize; + public string Align; + public string Placeholder; + public Color PlaceholderColor; + public int CharacterLimit; + + } + + /// + /// Button type + /// + public enum ReturnKeyType + { + Default, + Next, + Done, + Search + } + + /// + /// Input type + /// + public enum InputType + { + AutoCorrect, + Password + } + + /// + /// Keyboard type + /// + public enum KeyboardType + { + ASCIICapable, + NumbersAndPunctuation, + URL, + NumberPad, + PhonePad, + NamePhonePad, + EmailAddress + } + + /// + /// "Done" button visible (for iOS) + /// + public bool IsWithDoneButton = true; + /// + /// "(x)" button visible (for iOS) + /// + public bool IsWithClearButton = true; + /// + /// button type + /// + public ReturnKeyType ReturnKey; + /// + /// input type + /// + public InputType Type; + /// + /// keyboard type + /// + public KeyboardType Keyboard; + /// + /// action when Return pressed + /// + public event Action ReturnPressed; + /// + /// action when Focus changed + /// + public event Action FocusChanged = (b) => { }; + /// + /// event when Return pressed + /// + public UnityEngine.Events.UnityEvent OnReturnPressed; + /// + /// mobile input creation flag + /// + private bool _isMobileInputCreated = false; + /// + /// InputField object + /// + private InputField _inputObject; + /// + /// Text object from _inputObject + /// + private Text _inputObjectText; + /// + /// set focus on create + /// + private bool _isFocusOnCreate; + /// + /// set visible on create + /// + private bool _isVisibleOnCreate = true; + /// + /// last inputfield position + /// + private Rect _lastRect; + /// + /// config + /// + private MobileInputConfig _config; + + // event for plugin communication + + private const string CREATE = "CREATE_EDIT"; + private const string REMOVE = "REMOVE_EDIT"; + private const string SET_TEXT = "SET_TEXT"; + private const string SET_RECT = "SET_RECT"; + private const string SET_FOCUS = "SET_FOCUS"; + private const string ON_FOCUS = "ON_FOCUS"; + private const string ON_UNFOCUS = "ON_UNFOCUS"; + private const string SET_VISIBLE = "SET_VISIBLE"; + private const string TEXT_CHANGE = "TEXT_CHANGE"; + private const string TEXT_END_EDIT = "TEXT_END_EDIT"; + private const string ANDROID_KEY_DOWN = "ANDROID_KEY_DOWN"; + private const string RETURN_PRESSED = "RETURN_PRESSED"; + private const string READY = "READY"; + + /// + /// Constructor + /// + private void Awake() + { + _inputObject = this.GetComponent(); + if (_inputObject == null) + { #if DEBUG - Debug.LogErrorFormat ("No InputField found {0} MobileInput Error", this.name); + Debug.LogErrorFormat("No InputField found {0} MobileInput Error", this.name); #endif - throw new MissingComponentException (); - } - _inputObjectText = _inputObject.textComponent; - } - - /// - /// Create mobile input on Start with coroutine - /// - protected override void Start () { - base.Start (); - StartCoroutine (InitialzieOnNextFrame ()); - } - - /// - /// Show on enable - /// - private void OnEnable () { - if (_isMobileInputCreated) - this.SetVisible (true); - } - - /// - /// Hide on disable - /// - private void OnDisable () { - if (_isMobileInputCreated) { - this.SetFocus (false); - this.SetVisible (false); - } - } - - /// - /// Destructor - /// - protected override void OnDestroy () { - RemoveNative (); - base.OnDestroy (); - } - - /// - /// Handler for app focus lost - /// - /// - private void OnApplicationFocus (bool hasFocus) { - if (!_isMobileInputCreated || !this.Visible) - return; - this.SetVisible (hasFocus); - } - - /// - /// Current InputField for external access - /// - public InputField InputField { - get { - return _inputObject; - } - } - - /// - /// Mobile input visible - /// - /// true | false - public bool Visible { - get; - private set; - } - - /// - /// Mobile input text - /// - public string Text { - get { - return _inputObject.text; - } - set { - _inputObject.text = value; - SetTextNative (value); - } - } - - /// - /// Initialization coroutine - /// - private IEnumerator InitialzieOnNextFrame () { - yield return null; - this.PrepareNativeEdit (); + throw new MissingComponentException(); + } + _inputObjectText = _inputObject.textComponent; + } + + /// + /// Create mobile input on Start with coroutine + /// + protected override void Start() + { + base.Start(); + StartCoroutine(InitialzieOnNextFrame()); + } + + /// + /// Show on enable + /// + private void OnEnable() + { + if (_isMobileInputCreated) + this.SetVisible(true); + } + + /// + /// Hide on disable + /// + private void OnDisable() + { + if (_isMobileInputCreated) + { + this.SetFocus(false); + this.SetVisible(false); + } + } + + /// + /// Destructor + /// + protected override void OnDestroy() + { + RemoveNative(); + base.OnDestroy(); + } + + /// + /// Handler for app focus lost + /// + /// + private void OnApplicationFocus(bool hasFocus) + { + if (!_isMobileInputCreated || !this.Visible) + return; + this.SetVisible(hasFocus); + } + + /// + /// Current InputField for external access + /// + public InputField InputField + { + get + { + return _inputObject; + } + } + + /// + /// Mobile input visible + /// + /// true | false + public bool Visible + { + get; + private set; + } + + /// + /// Mobile input text + /// + public string Text + { + get + { + return _inputObject.text; + } + set + { + _inputObject.text = value; + SetTextNative(value); + } + } + + /// + /// Initialization coroutine + /// + private IEnumerator InitialzieOnNextFrame() + { + yield return null; + this.PrepareNativeEdit(); #if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR this.CreateNativeEdit (); this.SetTextNative (this._inputObjectText.text); @@ -235,28 +266,37 @@ private IEnumerator InitialzieOnNextFrame () { _inputObjectText.enabled = false; _inputObject.enabled = false; #endif - } - - /// - /// Check position on each frame - /// If changed - send to plugin - /// It's need when app rotate on input field chage position - /// - private void Update () { + } + + /// + /// Check position on each frame + /// If changed - send to plugin + /// It's need when app rotate on input field chage position + /// + private void Update() + { #if UNITY_ANDROID && !UNITY_EDITOR - this.UpdateForceKeyeventForAndroid (); + this.UpdateForceKeyeventForAndroid (); #endif - if (this._inputObject != null && _isMobileInputCreated) { - SetRectNative (this._inputObjectText.rectTransform); - } - } - - /// - /// Get bounds and calc for current screen size - /// - /// recttranform - /// rect - Rect GetScreenRectFromRectTransform (RectTransform rect) { + if (this._inputObject != null && _isMobileInputCreated) + { +#if UNITY_IOS + if (Input.GetMouseButtonDown(0) && !this._inputObjectText.rectTransform.rect.Contains(Input.mousePosition)) + { + Hide(); + return; + } +#endif + SetRectNative(this._inputObjectText.rectTransform); + } + } + + /// + /// Get bounds and calc for current screen size + /// + /// recttranform + /// rect + Rect GetScreenRectFromRectTransform (RectTransform rect) { Vector3[] corners = new Vector3[4]; rect.GetWorldCorners (corners); float xMin = float.PositiveInfinity; @@ -349,12 +389,19 @@ public override void Hide () { private IEnumerator PluginsMessageRoutine (JsonObject data) { yield return null; string msg = data["msg"]; - if (msg.Equals (TEXT_CHANGE)) { - string text = data["text"]; - this.onTextChange (text); - } else if (msg.Equals (READY)) { - this.Ready (); - } else if (msg.Equals (TEXT_END_EDIT)) { + if (msg.Equals(TEXT_CHANGE)) { + string text = data["text"]; + this.onTextChange(text); + } + else if (msg.Equals(READY)) { + this.Ready(); + } + else if (msg.Equals(ON_FOCUS)) { + FocusChanged(true); + } + else if (msg.Equals(ON_UNFOCUS)){ + FocusChanged(false); + } else if (msg.Equals (TEXT_END_EDIT)) { string text = data["text"]; this.onTextEditEnd (text); } else if (msg.Equals (RETURN_PRESSED)) { @@ -389,7 +436,8 @@ private void CreateNativeEdit () { data["font_size"] = _config.FontSize; data["content_type"] = _config.ContentType; data["align"] = _config.Align; - data["with_done_button"] = this.IsWithDoneButton; + data["with_done_button"] = this.IsWithDoneButton; + data["with_clear_button"] = this.IsWithClearButton; data["placeholder"] = _config.Placeholder; data["placeholder_color_r"] = _config.PlaceholderColor.r; data["placeholder_color_g"] = _config.PlaceholderColor.g;