Xamarin.iOS Draw a Border for bottom of the UITextField / ViewDidAppear is too late - iphone

I'm coding in Xamarin.iOs and I'd like to add a border for bottom of the UITextField.
So it's simple, I've googled it and (I personalized it to Xamarin.ios and) I have this code from this link.
UITextField _textField = new UITextField();
_textField.Placeholder = placeHolder;
_textField.AutocapitalizationType = autocap.Value;
_textField.AutocorrectionType = uitextAutocorrect.Value;
_textField.BorderStyle = borderstyle.Value;
_textField.SecureTextEntry = secureTextEntry.Value;
_textField.KeyboardType = uiKeyboardType.Value;
return _textField;
As you know I cannot put this part of code in constructor of my ViewController and also in ViewWillAppear. So I have to put it in ViewDidAppear, BUT it's too late, it means that when I run ViewController, it show the textField without borders, and just after a few milliseconds, the border will appear which is toooo late for me.
Any idea for this display problem?
EDIT:
So I ask my question in much more detail :
here is my complete code:
public class ChangePasswordViewController: UIViewController
{
//private MainViewModel _viewModel;
private UILabel _oldPasswordLabel;
private UITextField _oldPasswordTextField;
private UILabel _newPasswordLabel;
private UITextField _newPasswordTextField;
private UILabel _confirmPasswordLabel;
private UITextField _confirmPasswordTextField;
private User currentUser;
private UIButton _saveNewPassworBtn;
public ChangePasswordViewController(User user)
{
currentUser = user;
}
private void _saveNewPassworBtn_TouchUpInside(object sender, EventArgs e)
{
//do sth
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
//_viewModel = new MainViewModel();
Title = Texts.ChangePassword;
View.BackgroundColor = UIColor.White;
_oldPasswordLabel = InitUILabel(Texts.OldPasswordTxt, alignment: UITextAlignment.Right);
_oldPasswordLabel.Font = UIFont.BoldSystemFontOfSize(14);
_oldPasswordLabel.AdjustsFontSizeToFitWidth = true;
_oldPasswordTextField = InitUITextField(Texts.OldPassword, secureTextEntry: true);
this._oldPasswordTextField.ShouldReturn += (textField) => {
_newPasswordTextField.BecomeFirstResponder();
return true;
};
_oldPasswordTextField.BorderStyle = UITextBorderStyle.None;
_newPasswordLabel = InitUILabel(Texts.NewPasswordTxt, alignment: UITextAlignment.Right);
_newPasswordLabel.Font = UIFont.BoldSystemFontOfSize(14);
_newPasswordTextField = InitUITextField(Texts.NewPassword, secureTextEntry: true);
this._newPasswordTextField.ShouldReturn += (textField) => {
_confirmPasswordTextField.BecomeFirstResponder();
return true;
};
_newPasswordTextField.BorderStyle = UITextBorderStyle.None;
_confirmPasswordLabel = InitUILabel(Texts.ConfirmPasswordTxt, alignment: UITextAlignment.Right);
_confirmPasswordLabel.Font = UIFont.BoldSystemFontOfSize(14);
_confirmPasswordTextField = InitUITextField(Texts.NewPassword, secureTextEntry: true);
this._confirmPasswordTextField.ShouldReturn += (textField) => {
textField.ResignFirstResponder();
return true;
};
_confirmPasswordTextField.BorderStyle = UITextBorderStyle.None;
_saveNewPassworBtn = InitUIButton(Texts.Save, _saveNewPassworBtn_TouchUpInside, Colors.MainColor, UIColor.White);
View.AddSubviews(_oldPasswordLabel, _oldPasswordTextField, _newPasswordLabel, _newPasswordTextField,
_saveNewPassworBtn, _confirmPasswordLabel, _confirmPasswordTextField);
//
//constraints
var hMargin = 10;
var hMiniMargin = 5;
var vMargin = 10;
View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
View.AddConstraints(
_oldPasswordLabel.AtTopOf(View, 100),
_oldPasswordLabel.AtLeftOf(View, hMargin),
_oldPasswordTextField.Below(_oldPasswordLabel, hMiniMargin),
_oldPasswordTextField.AtLeftOf(View, hMargin),
_oldPasswordTextField.WithSameWidth(View).Minus(hMargin * 2),
_newPasswordLabel.Below(_oldPasswordTextField, vMargin),
_newPasswordLabel.AtLeftOf(View, hMargin),
_newPasswordTextField.Below(_newPasswordLabel, hMiniMargin),
_newPasswordTextField.AtLeftOf(View, hMargin),
_newPasswordTextField.WithSameWidth(View).Minus(hMargin * 2),
_confirmPasswordLabel.Below(_newPasswordTextField, vMargin),
_confirmPasswordLabel.AtLeftOf(View, hMargin),
_confirmPasswordTextField.Below(_confirmPasswordLabel, hMiniMargin),
_confirmPasswordTextField.AtLeftOf(View, hMargin),
_confirmPasswordTextField.WithSameWidth(View).Minus(hMargin * 2),
_saveNewPassworBtn.Below(_confirmPasswordTextField, vMargin * 3),
_saveNewPassworBtn.WithSameWidth(View).Minus(20),
_saveNewPassworBtn.AtLeftOf(View, 10)
);
_newPasswordTextField = SetBottomBorderLine(_newPasswordTextField);
_confirmPasswordTextField = SetBottomBorderLine(_confirmPasswordTextField);
_oldPasswordTextField = SetBottomBorderLine(_oldPasswordTextField);
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
this.NavigationItem.SetLeftBarButtonItem(new UIBarButtonItem(Texts.Cancel,UIBarButtonItemStyle.Plain, (sender, args) =>
{
this.NavigationController.SetNavigationBarHidden(false, false);
this.NavigationController.PushViewController(new ProfileViewController(), false);
}), true);
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
}
}
In these lines:
_newPasswordTextField = SetBottomBorderLine(_newPasswordTextField);
_confirmPasswordTextField = SetBottomBorderLine(_confirmPasswordTextField);
_oldPasswordTextField = SetBottomBorderLine(_oldPasswordTextField);
I put the border for my textfields BUT! If I put these line in ViewDidLoad or ViewWillAppear or ViewDidLayoutSubviews, it doesn't show the changes and if I put them in ViewDidAppear, it's shows perfectly with some milliseconds delay (after showing the content of my page!!!). Do you have any solution for me?

It caused by using Cirrious.FluentLayouts.
When we set the Constraints in ViewDidLoad, those control will not finish rendering before ViewDidAppear .
Print the frame of those textfields in ViewDidLoad, ViewWillAppear ,ViewDidAppear , you can find that only in ViewDidAppear the frame is not equal (0,0,0,0).
To solve the problem, you can add View.LayoutIfNeeded in ViewDidLoad to force update the view.
View.AddConstraints(
//xxx
);
View.LayoutIfNeeded(); //Add this
_newPasswordTextField = SetBottomBorderLine(_newPasswordTextField);
_confirmPasswordTextField = SetBottomBorderLine(_confirmPasswordTextField);
_oldPasswordTextField = SetBottomBorderLine(_oldPasswordTextField);

Related

How to add button in scroll View using script in unity

I am new to unity and am using unity 2020.3.26f1 . I am receiving an array of names from server. I want to make buttons dynamically using those names inside scroll view using c# script and assign on Click() that simply prints the name of button when its clicked. I just don't know how to create button dynamically. Following is the script I have attached to scroll View;
public string allNames;
void Start()
{
StartCoroutine(getNames());
}
IEnumerator getNames()
{
UnityWebRequest www = UnityWebRequest.Get("http://localhost:8080/names");
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
}
else
{
allNames = www.downloadHandler.text;
allNames = allNames.Replace("[", "");
allNames = allNames.Replace("]", "");
allNames = allNames.Replace("\"","");
string[] separatedNames = allNames.Split(',');
for (int i = 0; i < separatedNames.Length; i++)
{
Debug.Log(separatedNames[i]);
//make buttons here and attach them to scroll View
}
}
}
I found a video that applied #ShafqatJamilKhan suggestion. Posting my code here for reference.
//content reference of scroll view
[SerializeField] Transform contentPanel;
[SerializeField] GameObject buttonPrefab;
void Start()
{
StartCoroutine(getNames());
}
IEnumerator getNames()
{
UnityWebRequest www = UnityWebRequest.Get("http://localhost:8080/names");
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
}
else
{
string allNames = www.downloadHandler.text;
allNames = allNames.Replace("[", "");
allNames = allNames.Replace("]", "");
allNames = allNames.Replace("\"","");
// prefab button y position and yPosition should be the same.
float yPosition = 115;
string[] separatedNames = allNames.Split(',');
for (int i = 0; i < separatedNames.Length; i++)
{
GameObject button = (GameObject)Instantiate(buttonPrefab);
string name = separatedNames[i];
button.GetComponentInChildren<Text>().text = name;
button.GetComponent<Button>().onClick.AddListener(
// your function whatever you want to do
() => { customFunction(name); });
// applying y positions so the buttons dont overlap
button.transform.SetPositionAndRotation(new Vector3(0.0f, yPosition, 0.0f), new Quaternion(0.0f, 0.0f, 0.0f,0.0f));
button.transform.SetParent(contentPanel,false);
yPosition -= 35;
}
}
}
Make a nice button and save it as prefab.
Instantiate it or Pool it.
Add onClick events.
GameObject buttonPrefab;
void MyAwesomeCreator()
{
GameObject go = Instantiate(buttonPrefab);
var button = GetComponent<UnityEngine.UI.Button>();
button.onClick.AddListener(() => FooOnClick());
}
void FooOnClick()
{
Debug.Log("Ta-Da!");
}
Copied from Unity Forum

how to add flyout text to flyout in button programatically

Im a generating this button and i would like to set text in the flyout
var button = new Button();
button.Height = height;
button.Width = width;
button.Margin = new Thickness(left, top, 0, 0);
button.BorderBrush = new SolidColorBrush(Windows.UI.Colors.Red);
button.BorderThickness = new Thickness(2);
button.Background = new SolidColorBrush(Windows.UI.Colors.Transparent);
button.Flyout = new Flyout();
how do i set content of button.Flyout?
how do i set content of button.Flyout?
You could pass button instance to the follow method.
public void AddFlyoutToBtn(Button TargetBtn)
{
TargetBtn.Flyout = new Flyout()
{
Content = new StackPanel
{
Children =
{
new TextBlock
{
Text = "All items will be removed. Do you want to continue?",
Margin = new Thickness(10, 10, 0, 0)
},
new Button
{
Content = "Yes, empty my cart"
}
}
}
};
}

Unity3D GUI.Label is not displayed

I am currently trying to make "Welcome!" string and a button appear on screen by using the GUI Label and GUILayout Button, but it does not appear and there are not any errors that I know of. Unity emulator is ok, but the "Welcome!" string is not displayed in android.
Here is my code, can someone please tell me my problem and if I might have forgotten to do something.
public class MainMenu : MonoBehaviour
{
public GUISkin Skin;
public Texture btnTexture;
public void Awake() { }
public void OnGUI()
{
if (this.Skin != null)
{
GUI.skin = this.Skin;
}
GUI.skin.button.fontSize = 30;
Rect content = new Rect(30, 100, Screen.width-60, Screen.height-200);
GUILayout.BeginArea(content);
GUILayout.BeginHorizontal();
GUIStyle TextStyle = new GUIStyle(GUI.skin.label);
TextStyle.fontSize = 50;
// Load and set Font
Font myFont = (Font)Resources.Load("font/stingray", typeof(Font));
GUI.skin.font = myFont;
// Set color for selected and unselected
TextStyle.normal.textColor = Color.yellow;
TextStyle.hover.textColor = Color.yellow;
// Display and set the style in string
GUI.Label(new Rect(50,50,300,70), "Welcome!", TextStyle);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Join", GUILayout.Width(300), GUILayout.Height(80)))
{
SceneManager.LoadSceneAsync("SingleMenu");
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
void Start () { }
void Update () { }
}

monotouch dispose UIWebView

Using a UIWebView in my application and I cant seem to release the memory it's using.
I have a UIButton which loads a view controller which holds the UIWebView.
When the webView is loaded the Real Memory (checking it using Instruments) rises but doesn't get lower after my attempts to release it.
When the button is pressed:
if (childBroswer != null)
{
childBroswer.Dispose();
childBroswer = null;
}
childBroswer = new ChildBrowser(url);
AppDelegate d = (AppDelegate)UIApplication.SharedApplication.Delegate;
if ( d.rootNavigationController.RespondsToSelector(
new MonoTouch.ObjCRuntime.Selector("presentViewController:animated:completion:")))
{
d.rootNavigationController.PresentViewController(childBroswer, true, null);
}
else
{
d.rootNavigationController.PresentModalViewController(childBroswer, true);
}
Child browser class:
public partial class ChildBrowser : UIViewController
{
public string _url {get;set;}
UIActivityIndicatorView activityIndicator;
UIWebView webBrowser;
NSUrl nsURL;
NSUrlRequest nsURLRequest;
public ChildBrowser (string url) : base ("ChildBrowser", null)
{
nsURL = new NSUrl(url);
nsURLRequest = new NSUrlRequest(nsURL);
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
if (webBrowser == null)
{
webBrowser = new UIWebView(new RectangleF(0,41,320,380));
}
this.Add(webBrowser);
webBrowser.LoadFinished += (object sender, EventArgs e) => {
activityIndicator.StopAnimating();
} ;
webBrowser.LoadStarted += (object sender, EventArgs e) => {
if (activityIndicator == null)
{
activityIndicator = new UIActivityIndicatorView(new RectangleF(UIScreen.MainScreen.Bounds.Width / 2 - 50,
UIScreen.MainScreen.Bounds.Height / 2 - 30,100,100));
activityIndicator.Color = UIColor.Black;
}
activityIndicator.StartAnimating();
this.Add(activityIndicator);
} ;
webBrowser.LoadHtmlString("<html><head></head><body></body></html>",null); //stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML = \"\";"];
webBrowser.LoadRequest(nsURLRequest);
closeBrowser.TouchUpInside += handleClose;
// Perform any additional setup after loading the view, typically from a nib.
}
private void handleClose(object sender, EventArgs e)
{
webBrowser.Delegate = null;
webBrowser.StopLoading();
webBrowser.Dispose();
DismissViewController(true,delegate {
closeBrowser.TouchUpInside -= handleClose;
webBrowser.RemoveFromSuperview();
this.Dispose();
} );
}
public override void ViewWillAppear (bool animated)
{
base.ViewWillAppear (animated);
}
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(true);
//webBrowser.RemoveFromSuperview();
}
public void webViewDidFinishLoad(UIWebView webView)
{
//string u = "";
}
protected override void Dispose(bool disposing)
{
ReleaseDesignerOutlets();
base.Dispose(disposing);
}
What am i missing?
Thank you!
Memory for native objects is not reclaimed when you call Dispose. Calling Dispose only drops the managed reference - but the ObjC runtime (reference counted) won't free the object until there's no native reference as well. See this Q&A for more details...
This means that code such as:
this.Add(webBrowser);
will create such a native reference and is likely (i.e. if not removed elsewhere) to keep the webBrowser instance alive as long as this is alive. If you keep Adding then you memory usage will keep growing.
I'm the OP - It seems that releasing the memory usage of UIWebView is quite hard, even when doing so in Objective-C.
What I have eventually done, which didn't solve the problem but improved the memory release is adding the following lines when closing the UIWebView:
NSUrlCache.SharedCache.RemoveAllCachedResponses();
NSUrlCache.SharedCache.DiskCapacity = 0;
NSUrlCache.SharedCache.MemoryCapacity = 0;
webView.LoadHtmlString("",null);
webView.EvaluateJavascript("var body=document.getElementsByTagName('body')[0];body.style.backgroundColor=(body.style.backgroundColor=='')?'white':'';");
webView.EvaluateJavascript("document.open();document.close()");
webView.StopLoading();
webView.Delegate = null;
webView.RemoveFromSuperview();
webView.Dispose();

How do I style RootElement

I need a way to style Monotouch Dialogs RootElement. I need to change the background and font color.
I'm have created a custom RootElement as below
public class ActivityRootElement : RootElement
{
public ActivityRootElement (string caption) : base (caption)
{
}
public ActivityRootElement(string caption, Func<RootElement, UIViewController> createOnSelected) : base (caption, createOnSelected)
{
}
public ActivityRootElement(string caption, int section, int element) : base (caption, section, element)
{
}
public ActivityRootElement(string caption, Group group) : base (caption, group)
{
}
public override UITableViewCell GetCell (UITableView tv)
{
tv.BackgroundColor = Settings.RootBackgroundColour;
return base.GetCell (tv);
}
protected override void PrepareDialogViewController(UIViewController dvc)
{
dvc.View.BackgroundColor = Settings.RootBackgroundColour;
base.PrepareDialogViewController(dvc);
}
}
I am then calling the custom root element as below passing in a custom DialogController
section.Add (new ActivityRootElement(activity.Name, (RootElement e) => {
return new ActivityHistoryDialogViewController (e,true);
}));
The root Element style is not been applied. Any help would be apprciated!!
If you want the color to be the only thing you see in the TableViewController, you need to set the BackgrounView to null. There is a view overtop to apply the styling, which will hide the color you are looking for.
Try this:
public override UITableViewCell GetCell (UITableView tv)
{
tv.BackgroundColor = Settings.RootBackgroundColour;
tv.BackgroundView = null;
return base.GetCell (tv);
}
protected override void PrepareDialogViewController(UIViewController dvc)
{
dvc.TableView.BackgroundColor = Settings.RootBackgroundColour;
dvc.TableView.BackgroundView = null;
base.PrepareDialogViewController(dvc);
}
In order to get this to work, I had to override the MakeViewController method and cast the UIViewController that it normally returns to a UITableViewController, then make my edits.
protected override UIViewController MakeViewController()
{
var vc = (UITableViewController) base.MakeViewController();
vc.TableView.BackgroundView = null;
vc.View.BackgroundColor = UIColor.Red; //or whatever color you like
return vc;
}