UIDatePicker breaks when using UIDatePickerMode.DateAndTime - ios

I'm creating an app with Monotouch 5 and I'm having a problem with creating a datepicker with the mode UIDatePickerMode.DateAndTime on iOS 4.3 or lower when running my app in an iPad Simulator. The DatePicker is always broken, although the dimensions I set for it's frame and the surrounding view are perfectly fine.
This is how it looks like on an iPad Simulator with iOS 4.3:
http://screencast.com/t/isIRcUcKCF5
and this is how it looks on an iPad Simulator with iOS 5.0:
http://screencast.com/t/UxPTpR0Btzb
This problem does not occur on iPhone Simulators or real devices. I know it also does not occur on real iPad devices with iOS 5, but I could not test 4.3 or lower because I have no such device.
The source code for creating the date picker is as follows:
public override void Selected (MonoTouch.Dialog.DialogViewController dvc, UITableView tableView, NSIndexPath path)
{
var vc = new MyViewController (this) {
Autorotate = dvc.Autorotate
};
datePicker = CreatePicker ();
datePicker.Frame = PickerFrameWithSize (datePicker.SizeThatFits (SizeF.Empty));
//vc.View encompasses the entire, screen so there is plenty of space available for the date picker
vc.View.BackgroundColor = UIColor.Black;
vc.View.AddSubview (datePicker);
dvc.ActivateController (vc);
}
public virtual UIDatePicker CreatePicker ()
{
var picker = new UIDatePicker (RectangleF.Empty){
AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
Mode = UIDatePickerMode.DateAndTime,
Date = DateValue,
};
return picker;
}
static RectangleF PickerFrameWithSize (SizeF size)
{
var screenRect = UIScreen.MainScreen.ApplicationFrame;
float fY = 0, fX = 0;
switch (UIApplication.SharedApplication.StatusBarOrientation){
case UIInterfaceOrientation.LandscapeLeft:
case UIInterfaceOrientation.LandscapeRight:
fX = (screenRect.Height - size.Width) /2;
fY = (screenRect.Width - size.Height) / 2 -17;
break;
case UIInterfaceOrientation.Portrait:
case UIInterfaceOrientation.PortraitUpsideDown:
fX = (screenRect.Width - size.Width) / 2;
fY = (screenRect.Height - size.Height) / 2 - 25;
break;
}
// calculated values:
// fx: 224
// fy: 369
// size.Width: 320
// size.Height: 320
return new RectangleF (fX, fY, size.Width, size.Height);
}
When I am using a datepicker with the modes UIDatePickerMode.Date or UIDatePickerMode.Time, the problem does not occur.
The problem looks just like blank UIDatePicker on iPad in mode UIDatePickerModeDateAndTime, but the fix described there does not work in my case for some weird reason.
Any hints on how to work around this bug would be greatly appreciated.
Thanks,
Adrian

I still don't have a clue how to make the code above work, but I managed to work around this iOS bug by using a UIPopupView for displaying the calendar instead.

Related

Hiding the TabBar on iOS 11 using Xamarin is leaving a white rectangle

Prior to iOS 11, I was using this code inside a custom renderer for the TabPage to conditionally hide the TabBar in my app:
private void ToggleTabs(object sender, bool hideTabs)
{
TabBar.Hidden = hideTabs;
TabBar.Frame = TabBar.Hidden
? new CGRect(TabBar.Frame.X, TabBar.Frame.Y, TabBar.Frame.Width, 0)
: new CGRect(TabBar.Frame.X, TabBar.Frame.Y, TabBar.Frame.Width, tabBarHeight);
}
where tabBarHeight is calculated when the TabBar is constructed (it should always be 49 according to the docs, but I hate magic numbers).
The problem that I'm now running into is that even though I'm collapsing the frame, there is still a white rectangle left where the tab bar used to be. I have only noticed this behavior on devices running iOS 11 deployed from XCode 9.
I found some information about SafeAreaInsets that I thought may have been causing the problem, but 0 is always returned unless I'm running on an iPhone X, so that seems to have been a bust.
It looks like the iOS 11 SDK may be to blame, but I can't figure out the work around.
This worked for me:
TabBar.Hidden = tabBarHidden;
// The solution to the space left behind the invisible tab bar
if (tabBarHidden)
{
View.Subviews[1].Frame = new CoreGraphics.CGRect(View.Subviews[1].Frame.X, View.Subviews[1].Frame.Y,
View.Subviews[1].Frame.Width, 0);
View.Subviews[0].Frame = new CoreGraphics.CGRect(View.Subviews[0].Frame.X, View.Subviews[0].Frame.Y,
View.Subviews[0].Frame.Width, View.Subviews[0].Frame.Height + 49);
}
else
{
View.Subviews[1].Frame = new CoreGraphics.CGRect(View.Subviews[1].Frame.X, View.Subviews[1].Frame.Y,
View.Subviews[1].Frame.Width, 49);
View.Subviews[0].Frame = new CoreGraphics.CGRect(View.Subviews[0].Frame.X, View.Subviews[0].Frame.Y,
View.Subviews[0].Frame.Width, View.Subviews[0].Frame.Height - 49);
}
Had to add a little tweak for when the phone gets rotated, the views broke again, so this code also gets called when the rotation happens. The little wiggle of the view height seems to sort it all out... Very Hacky but 3-4 hrs later, I accepted the hack and moved on!
if (RootTabPage._fullScreen)
{
View.Subviews[1].Frame = new CoreGraphics.CGRect(View.Subviews[1].Frame.X, View.Subviews[1].Frame.Y,
View.Subviews[1].Frame.Width, 0);
if( View.Frame.Height == View.Subviews[0].Frame.Height )
View.Subviews[0].Frame = new CoreGraphics.CGRect(View.Subviews[0].Frame.X, View.Subviews[0].Frame.Y,
View.Subviews[0].Frame.Width, View.Frame.Height + 2 );
else
View.Subviews[0].Frame = new CoreGraphics.CGRect(View.Subviews[0].Frame.X, View.Subviews[0].Frame.Y,
View.Subviews[0].Frame.Width, View.Frame.Height + 3 );
}
else
{
View.Subviews[1].Frame = new CoreGraphics.CGRect(View.Subviews[1].Frame.X, View.Subviews[1].Frame.Y,
View.Subviews[1].Frame.Width, th);
View.Subviews[0].Frame = new CoreGraphics.CGRect(View.Subviews[0].Frame.X, View.Subviews[0].Frame.Y,
View.Subviews[0].Frame.Width, View.Frame.Height );
}

Access iOS Control Center using appium

I am trying to open the Control Center using appium and the following code:
int halfWidth = driver.manage().window().getSize().width / 2;
int screenHeight = driver.manage().window().getSize().height;
driver.swipe(halfWidth, screenHeight-5, halfWidth, screenHeight-300, 500); // driver is instance of IOSDriver
Instead of opening control centre the app simply draws on the screen upwards from the bottom (using coordinates input). Anyone know how to open Control Center using appium and swipe (or any other way)?
Thanks, Charlie
We can do this. I tried in Appium 1.4.13 and I am able to change settings.
I used below code to change the settings in my iPadAir2.
int height = driver.findElementByClassName("UIAWindow").getSize().getHeight();
int width = driver.findElementByClassName("UIAWindow").getSize().getWidth();
driver.swipe(width-100, height, width-100, height-200, 500);
driver.findElementByAccessibilityId("Wi-Fi").click();
Appium 1.6.5, You can use swipe method, bellow my Python code:
window_size = self.driver.get_window_size() # this returns dictionary
el = self.driver.find_element(*self.configuration.CommonScreen.WEB_VIEW)
action = TouchAction(self.driver)
start_x = window_size["width"] * 0.5
start_y = window_size["height"]
end_x = window_size["width"] * 0.5
end_y = window_size["height"] * 0.5
action.press(el, start_x, start_y).wait(100).move_to(el, end_x, end_y).release().perform()
I am able to toggle the Wifi OFF or turn Airplane mode ON using Appium 1.6.4-beta for iOS
Swipe up from the bottom of the screen
Click continue link
Click the Wifi or Airplane button
Swipe down from middle of screen
But this doesn't appear to be doing anything in the simulator. I have to actually turn off my computers internet connection to disable the internet on the simulator.
#iOSFindBy(xpath = "//XCUIElementTypeSwitch[#name='Wi-Fi']")
private MobileElement WIFI_MODE_BUTTON;
public void disableWifi() {
openToolBarMenu();
//if wifi is on/true then turn it off
if (WIFI_MODE_BUTTON.getAttribute("value") == "true" ) {
Autoscope.tap(WIFI_MODE_BUTTON);
}
closeToolBarMenu();
}
#iOSFindBy(xpath = "//XCUIElementTypeButton[#name='Continue']")
private MobileElement CONTINUE_BUTTON; //continue button on control center
public void openToolBarMenu() {
Autoscope.scrollFromBottomOfScreen();
if (Autoscope.isElementDisplayed(CONTINUE_BUTTON)) {
Autoscope.tap(CONTINUE_BUTTON);
}
}
static public void scrollFromBottomOfScreen() {
TouchAction touchAction = new TouchAction(autoscopeDriver);
int xStartPoint = Math.round(pixelWidth() / 2);
int yStartPoint = pixelHeight();
int yEndPoint = 0 - yStartPoint;
touchAction.press(xStartPoint, yStartPoint).moveTo(0, yEndPoint).release().perform();
}
This code will help in bringing up the Control center, while you are in your app, you can perform all the operations which are available in the Control Center
new TouchAction(DriverConfig.getInstance().getDriver()).press(point(250, 735)).waitAction(waitOptions(Duration.ofSeconds(3))).moveTo(point(250, -460)).release()
.perform();
C#: iOS 13.x
//Opening control center
var size = Driver.Manage().Window.Size;
var height = size.Height;
var width = size.Width;
var touchAction = new TouchAction(Driver);
touchAction.Press(width - 100, height).Wait(1000).MoveTo(width - 100, height - 200).Release().Perform();
//Clicking the WiFi button
Driver.FindElementByAccessibilityId("wifi-button").Click();
//Checking if WiFi enabled or not
var myElement = Driver.FindElementByAccessibilityId("wifi-button");
var result = myElement.GetAttribute("label");
if(!result.Contains("Wi-Fi, Not Connected") && !result.Equals("Wi-Fi"))
{
// WiFi connected
}
else
{
// WiFi Not connected
}
The idea is to simulate the swipe action you use to open Control Center on the corresponding iOS device. My device is iPhone 11 so it is swipe from the top right(to the right of the notch) down. My code is to swipe from position(x,y) (80% width, 0) to (80% width, 50% height)
Dimension size = getScreenSize();
int x = (size.getWidth() / 5) * 4;
int startY = 0;
int endY = size.getHeight() / 2;
new TouchAction(driver).press(PointOption.point(x, startY))
.waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1)))
.moveTo(PointOption.point(x, endY))
.release().perform();
Ok so after a fair amount of investigation it seems to me that this is not possible. If you really need this functionality then I think a tool like eggplant might be appropriate.

Could not make a CTParagraphStyleRef on iPhone

I found a strange problem when using the CoreText. Below is the code:
CGFloat headindent = theme.horizontalMargin.floatValue; // 10.0
CTParagraphStyleSetting head;
head.spec = kCTParagraphStyleSpecifierHeadIndent;
head.value = &headindent;
head.valueSize = sizeof(float);
CGFloat tailindent = -theme.horizontalMargin.floatValue; //-10.0
CTParagraphStyleSetting tail;
tail.spec = kCTParagraphStyleSpecifierTailIndent;
tail.value = &tailindent;
tail.valueSize = sizeof(float);
CGFloat firstlineindent =theme.horizontalMargin.floatValue;//10.0
CTParagraphStyleSetting firstline;
firstline.spec = kCTParagraphStyleSpecifierFirstLineHeadIndent;
firstline.value = &firstlineindent;
firstline.valueSize = sizeof(float);
CTParagraphStyleSetting settings[]={
head,
tail,
firstline,
};
CTParagraphStyleRef style = CTParagraphStyleCreate(settings, 3);
Then the style is added to make an attributed string. I get the values from a theme stored in CoreData. That works well when I run the app on iPad, but on iPhone the code does not work.
I made a breakpoint to check what is the problem, and I found that the theme values are both right in the iPad and iPhone condition,but the value of style ,which is a CTParagraphStyleRef, are all ZERO when running on iPhone.
Anyone has encounter same problem before? I just could not figure where is wrong.
Thanks for any help!
I just find the where the problem is...
In iPhone ,the sizeof(CGFloat) = 8 ,sizefo(float) = 4,
and in iPad , they are both 4.
But what still confused me is that since
typedef float CGFloat;
why their size are different.

strange droppable() bug on iPad, works on iPhone

I've tried various web searches, but I can't seem to find anything that relates to my problem.
To quickly delineate the problem:
HTML5 Cordova iOS app (7.1 -> 8.1)
uses draggable elements
I only have issues on the iPad, not on the iPhone
The HTML5 app itself works flawlessly in a web-browser
The app itself is a biology app that teaches translation - decoding RNA into a amino acid sequence, i.e. a protein.
For this, the user sees the sequence and drags the correct amino acid onto it. The amino acid is a draggable element and the target div is a droppable. One amino acid at a time a chain is built. Please refer to the screenshot to get an idea (can't embed yet).
http://i.stack.imgur.com/S4UpF.png
In order to fit all screens, I "transform: scale" the app accordingly (fixed size is ~850x550). And to get rid of the associated jQuery bug with draggable (object movement would also change with the scaling factor), I've followed the instructions at http://gungfoo.wordpress.com/2013/02/15/jquery-ui-resizabledraggable-with-transform-scale-set/
// scaling to fit viewport
// sizing the page
var myPage = $('.page');
var pageWidth=myPage.width();
var pageHeight=myPage.height();
// sizing the iFrame
var myFrame = $('.container');
var frameWidth=myFrame.width();
var frameHeight=myFrame.height();
// scaleFactor horizontal
var horizontalScale=pageWidth/frameWidth;
// scaleFactor vertiacal
var verticalScale=pageHeight/frameHeight;
// global zoomScale variable
var zoomScale = 1; // default, required for draggable debug
// if page fits vertically - scale horizontally
if ((frameHeight * horizontalScale) <= pageHeight) {
myFrame.css({
'transform': 'scale('+horizontalScale+')',
'transform-origin': 'top',
});
// adding vertical margin, if possible
if (pageHeight > frameHeight*horizontalScale) {
var heightDifference = pageHeight - frameHeight*horizontalScale;
myPage.css({
'margin-top': heightDifference/2,
'height': pageHeight - heightDifference/2,
});
}
zoomScale = horizontalScale;
// else scale vertically
} else {
myFrame.css({
'transform': 'scale('+verticalScale+')',
'transform-origin': 'top',
});
zoomScale = verticalScale;
}
// draggable + scale transform fixes (http://gungfoo.wordpress.com/2013/02/15/jquery-ui-resizabledraggable-with-transform-scale-set/)
function startFix(event, ui) {
ui.position.left = 0;
ui.position.top = 0;
}
function dragFix(event, ui) {
var changeLeft = ui.position.left - ui.originalPosition.left; // find change in left
var newLeft = ui.originalPosition.left + changeLeft / zoomScale; // adjust new left by our zoomScale
var changeTop = ui.position.top - ui.originalPosition.top; // find change in top
var newTop = ui.originalPosition.top + changeTop / zoomScale; // adjust new top by our zoomScale
ui.position.left = newLeft;
ui.position.top = newTop;
}
I've already got a beta version on iTunes connect and it works great on an iPhone. On iPads, however, the droppable area is oddly small and shifted. That is, the div seems to be properly rendered - it is the box with the dashed border.
Has anyone else encountered a similar bug? I really have no idea how to fix it.
I have managed to solve the problem.
The issue was probably based on the viewport meta tag (0.5 scaling) interacting badly with the transform:scale resizing.
Simply removing all viewport meta arguments have solved the problem.

Monotouch - UIActionSheet not displaying correctly on iPad

I have a UIActionSheet that works just fine on the iPhone simulator. It is presented when the user touches a UIButton.
Using the iPad, I believe UIActionSheets are wrapped into a UIPopupController.
When I call the same code using the iPad simulator, I get a thin "line" displayed, which looks like a UIPopupController (you can see the small arrow that usually points to a control). None of the content can be seen.
What is the correct way to use a UIActionSheet using the iPad with MonoTouch? Here is a bit of sample code I have been testing with - creating the UIActionSheet:
var actionSheet = new UIActionSheet () { Style = UIActionSheetStyle.BlackTranslucent };
actionSheet.Frame = actionSheetFrame;
actionSheet.Clicked += (s, e) => { Console.WriteLine ("Clicked on item {0}", e.ButtonIndex); };
actionSheet.AddSubview (doneButton);
Then, I am showing the actionsheet by calling the following from a button:
btnSay.TouchUpInside += (sender, e) => {
actionSheet.ShowFrom(tmpBtn.Frame, tmpView, false);
};
I get something like the attached screenshot when using the iPad simulator.
For reference, here is what the UIActionSheet looks like when using the iPhone simulator.
Note: The project is a universal single-view MonoTouch c# project.
Any pointers or help would be much appreciated!
I faced this same problem with a recent app I released to the app store.
When you show a UIActionSheet on iPad, iOS wraps the UIActionSheet in a UIPopoverView.
I used the following code to detect whether this is an iPad, and if it is, adjust the frame of the popover view:
const int CHROMEWIDTHLEFT = 9;
const int CHROMEWIDTHRIGHT = 8;
const int MARGIN = 50;
UIActionSheet _actionSheet;
...
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad) {
var popover = _actionSheet.Superview.Superview;
if (popover != null)
{
var x = _actionSheet.Frame.X + MARGIN;
var y = (UIScreen.MainScreen.ApplicationFrame.Height - _actionSheet.Frame.Height) / 2;
var width = _actionSheet.Frame.Width - (MARGIN * 2);
var height = _actionSheet.Frame.Height;
popover.Frame = new RectangleF (x, y, width, height);
_actionSheet.Frame = new RectangleF (x, y, width - (CHROMEWIDTHLEFT + CHROMEWIDTHRIGHT), height - (CHROMEWIDTHLEFT + CHROMEWIDTHRIGHT));
}
}
The example is based upon the Xamarin ActionSheet Date Picker here
I have put these up as a Gist (Normal and DatePicker)

Resources