This is how it's done - the important thing to note is that these style items go on your main app theme. Applying them directly to a specific input-field-only style/theme will not work.
Monday, 21 November 2016
Android material theme text input - changing colours of underline and floating label
Android styling/theming is an unholy mess, and I battled once again today with trying to get an input field to look like this:
This is how it's done - the important thing to note is that these style items go on your main app theme. Applying them directly to a specific input-field-only style/theme will not work.
This is how it's done - the important thing to note is that these style items go on your main app theme. Applying them directly to a specific input-field-only style/theme will not work.
Thursday, 3 November 2016
Android configuration qualifiers for alternative resources
I discovered today that there's loads more configuration qualifiers for providing alternative Android resources than I was aware of. Here's a handy table, taken from here.
Configuration
|
Example Qualifier
Values
|
---|---|
MCC and MNC
|
Examples:
mcc310 mcc310-mnc004 mcc208-mnc00 etc. |
Language and region
|
Examples:
en fr en-rUS fr-rFR fr-rCA etc. |
Layout Direction
|
ldrtl ldltr |
smallestWidth
|
sw Examples: sw320dp sw600dp sw720dp etc. |
Available width
|
w Examples: w720dp w1024dp etc. |
Available height
|
h Examples: h720dp h1024dp etc. |
Screen size
|
small normal large xlarge |
Screen aspect
|
long notlong |
Round screen
|
round notround |
Screen orientation
|
port land |
UI mode
|
car desk television |
Night mode
|
night notnight |
Screen pixel density (dpi)
|
ldpi mdpi hdpi xhdpi xxhdpi xxxhdpi nodpi tvdpi anydpi |
Touchscreen type
|
notouch finger |
Keyboard availability
|
keysexposed keyshidden keyssoft |
Primary text input method
|
nokeys qwerty 12key |
Navigation key availability
|
navexposed navhidden |
Primary non-touch navigation
method
|
nonav dpad trackball wheel |
Platform Version (API level)
|
Examples:
v3 v4 v7 etc. |
Monday, 31 October 2016
Creating a Toast equivalent in Xamarin iOS
I love Android's toast - the UI widget that allows us to tell the user something. It's simple and accessible, and something iOS lacks unless you find a plugin of some sort.
I've started a new app build recently, using Xamarin with native Android and iOS interfaces, and it was with great joy today that I found a Xamarin toast component for iOS.
Really simple to use with a using ToastIOS statement, and then the following kind of call:
I've started a new app build recently, using Xamarin with native Android and iOS interfaces, and it was with great joy today that I found a Xamarin toast component for iOS.
Really simple to use with a using ToastIOS statement, and then the following kind of call:
Toast.MakeText("Toast!", Toast.LENGTH_LONG) .SetFontSize(10) .SetGravity(ToastGravity.Center) .Show(ToastType.None);
Wednesday, 21 September 2016
Cordova phone keyboard 'Go' button event
If you need to capture the keyboard's 'Go' button event to automatically submit your form, do something like this, where I'm capturing keypresses during password field focus and checking to see if it's the Go button:
$('#loginPassword').on('keypress',function(e){ if (e.keyCode == 13) { loginPress(); } });
Monday, 29 August 2016
Headspace app store subscription phishing scam
I got quite a convincing phishing email today, it looked like a legit app store receipt for the Headspace, for £9.99. Many of the links go to Apple, and the link at the bottom 'Cancel and Manage my subscriptions' goes to something that looks like the App Store, but had my email address appended to the end.
I removed my address and visited the link http://rdr34623.3ls-secureapp.com/index.php If you input realistic data, it asks you for more information about yourself, and you may think you're correcting your erroneous headspace subscription.
If however, like me, you put in something like f***off@youscammers.com they redirect you to google with a search for something child-porn related. These people are real nice huh.
I removed my address and visited the link http://rdr34623.3ls-secureapp.com/index.php If you input realistic data, it asks you for more information about yourself, and you may think you're correcting your erroneous headspace subscription.
If however, like me, you put in something like f***off@youscammers.com they redirect you to google with a search for something child-porn related. These people are real nice huh.
Tuesday, 12 July 2016
JQuery mobile go back in history using Javascript
It's not clear at all in the documentation, but here it is:
$.mobile.back();And if you want to use this to make the Android back button work properly on your Cordova app, do this:
document.addEventListener("backbutton", onBackKeyDown, false); function onBackKeyDown() { $.mobile.back(); }
Friday, 1 July 2016
Tuesday, 21 June 2016
Cordova CLI build commands for Windows 10 and Windows Phone 8.1
By default the
cordova build
command produces two packages: Windows 8.1 and Windows Phone 8.1. To upgrade Windows package to version 10 the following configuration setting must be added to configuration file (config.xml
). name="windows-target-version" value="10.0" />
Once you add this setting
build
command will start producing Windows 10 packages.
You may decide that you want to build a particular version of your application targeting a particular OS (for example, you might have set that you want to target Windows 10, but you want to build for Windows Phone 8.1). To do this, you can use the
--appx
parameter:cordova build windows -- --appx=8.1-phone
The build system will ignore the preference set in config.xml for the target Windows version and strictly build a package for Windows Phone 8.1.
Valid values for the
--appx
flag are 8.1-win
, 8.1-phone
, and uap
(for Windows 10 Universal Apps). These options also apply to the cordova run
command.Component requires .NET Native compilation, not available targeting Windows10, AnyCPU
I've been having more pain with Cordova for Windows phones. I updated my Cordova CLI to 6.2.0 to overcome a problem I was having in Cordova/lib/prepare.js when building. It seems to work, but then a new problem appeared - or perhaps it was the same problem but with a more friendly message:
The following component requires .NET Native compilation which is not available when targeting 'Windows10' and 'AnyCPU'. Please consider changing the targeted processor architecture to one of the following: 'x86, x64, ARM' (if you are using command line this could be done by adding '--archs' parameter, for example: 'cordo va build windows --archs=x64'). C:\PathToMyProject\platforms\windows\plugins\cordova-plugin-globalization\GlobalizationProxy.winmd Error: C:\Program Files (x86)\MSBuild\14.0\bin\msbuild.exe: Command failed with exit code 1To overcome this I had to do what it said. The following command created a successful build:
cordova build windows --archs=x86
Implementing the Adobe DMP mobile SDKs on iOS and Android
If you're unfortunate enough to be tasked with this be prepared for it to take ten times longer than it should. You'll receive documentation that is woefully unclear, from different sources, and contradictory. When you need help you'll either not get it or wait ages for it. This has been nearly-the-worst DX I've had implementing a vendor's code, hot on the heels of ExactTarget.
But here's a tip, which I only found by rummaging through the code. Instead of silently failing, if you do this:
Then a whole new world of information will be available to you, and if you're lucky ADBMobile will actually tell you what's wrong. This debug setting was not mentioned in any of the setup documentation I was given (there is no troubleshooting section), and neither when I sought support several times from Adobe.
Had I been told about this from the start it would have saved several people a whole lot of time.
But here's a tip, which I only found by rummaging through the code. Instead of silently failing, if you do this:
[ADBMobile setDebugLogging:YES];
Then a whole new world of information will be available to you, and if you're lucky ADBMobile will actually tell you what's wrong. This debug setting was not mentioned in any of the setup documentation I was given (there is no troubleshooting section), and neither when I sought support several times from Adobe.
Had I been told about this from the start it would have saved several people a whole lot of time.
Wednesday, 8 June 2016
Android Xamarin AddJavascriptInterface
A recent change in my codeset to API 17 caused my javascript interfaces in a webview to fail. From 17 onwards it is now a requirement that you annotate your method with [Export] and [JavascriptInterface], like so:
[Export] [JavascriptInterface] public void Run() { //do your stuff }
Thursday, 26 May 2016
Get boolean value from JSON, in Obj C
myObject.MyBoolValue = [[myDictionary objectForKey:@"TheNameOfTheJsonValue"]boolValue];
Friday, 13 May 2016
Android Xamarin ViewPager cacheing - unable to renew contents
I just 'wasted' a couple of hours trying to resolve a problem with a ViewPager. I have a fragment that hosts a ViewPager of 7-10 fragments, all of which needed to be swapped out if the user selects a different value/setting. This was working fine in some cases, but when navigating away from the parent fragment and then returning, I seemed unable to get the ViewPager to update properly, showing either old or blank content.
I spent too long stepping through my code trying to work out if I'd missed something, but came up with nothing, and figured that there must be some kind of cacheing going on.
After some reading I learnt that I should be using FragmentStatePagerAdapter and not FragmentPagerAdapter. The difference is explained here.
This, combined with the below override in my adapter, finally solved my problem.
As ever, I remained indebted to StackOverflow, and this is the answer that resolved it for me.
I spent too long stepping through my code trying to work out if I'd missed something, but came up with nothing, and figured that there must be some kind of cacheing going on.
After some reading I learnt that I should be using FragmentStatePagerAdapter and not FragmentPagerAdapter. The difference is explained here.
This, combined with the below override in my adapter, finally solved my problem.
public override int GetItemPosition(Object objectValue) { return PositionNone; }
As ever, I remained indebted to StackOverflow, and this is the answer that resolved it for me.
Thursday, 12 May 2016
Friday, 22 April 2016
Invoke C# from Javascript in Android using Export attribute
I've been happily invoking C# from a webview in my Xamarin Android app for some while now, but this time I needed to send a parameter from my js. Using the basic Run() was no longer an option and so I turned to a solution using the Export attribute, which I first read about here.
Instead of:
Instead of:
public void Run() { //do your stuff }you do this:
[Export("customInvoke")] public void CustomInvoke(string myParameter) { //do your stuff }
Tuesday, 29 March 2016
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
How to stop an HTML input field thinking it knows best on mobile:
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
Monday, 28 March 2016
Capturing touch events in iOS/Android webviews
I have some HTML content that is shared between a Xamarin Android app and an ObjC/Swift native iOS app. In the HTML are a few buttons that need to trigger events in the native code of each app. The techniques for capturing these events are well documented, but one has to remember that a touch event might actually be a scroll or a swipe, and the use may not be trying to 'click' the element in question. I overcame this problem by using a boolean flag to see if we're moving:
var moved; $('.myElement').on('touchend', function(e){ if(moved != true){ //do your thing } }).on('touchmove', function(e){ moved = true; }).on('touchstart', function(){ moved = false; });
Thursday, 10 March 2016
Xamarin Android get image from Assets
var ims = AppContext.Assets.Open("path/to/my/file/in/assets");
var drawable = Drawable.CreateFromStream(ims, null);
imageView.SetImageDrawable(drawable);
Monday, 7 March 2016
Showing layout using bootstrap
Here's a cheeky little bit of css that will make your layout clear when you're building UI with bootsrap. Really handy for building and debugging:
[class*="span"] { background: #EEF; } [class*="span"] [class*="span"] { background: #FEE; }
Thursday, 3 March 2016
Xamarin Android JDK7 > JDK8
Note to self...it looks like it's ok to upgrade to JDK8. See this thread on the Xamarin forum.
Wednesday, 2 March 2016
Xamarin Android get drawable by filename
I had to tap into a carousel event and change a background image when it was swiped. The contents of the carousel were populated by a list of objects, with the image file name as a string property. I had to get the drawable with its filename, and prevent the process (getting the file from disk) blocking the UI. Once obtained I had to update the image on the UI thread.
ThreadPool.QueueUserWorkItem(o =>
{
var imgId = Resources.GetIdentifier(_tips[position].Image, "drawable", AppContext.PackageName);
var drawable = Resources.GetDrawable(imgId);
RunOnUiThread(() =>
{
_bgImage.SetImageDrawable(drawable);
});
});
Monday, 29 February 2016
iOS Swift animation - shake element on input error
We're used to seeing an input element shake when input has failed validation, like a person shaking their head at you. Here's the code to create the animation:
public func errorShake(element: UIView!){
let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.07
animation.repeatCount = 4
animation.autoreverses = true
animation.fromValue = NSValue(CGPoint: CGPointMake(element.center.x - 10, element.center.y))
animation.toValue = NSValue(CGPoint: CGPointMake(element.center.x + 10, element.center.y))
element.layer.addAnimation(animation, forKey: "position")
}
Thursday, 25 February 2016
Morph a view into another in Swift
Today I was tasked with morphing a button, when tapped, into another view that I'd already constructed of a bespoke date selector.
I achieved this by adding an extension to UIView, with a function that animates the bounds, frame and background colour of one view to another:
making it super easy to use:
I achieved this by adding an extension to UIView, with a function that animates the bounds, frame and background colour of one view to another:
func morphToView(duration:Double,delay:Double,toView:UIView){
UIView.animateWithDuration(duration, delay: delay, usingSpringWithDamping: 1.0, initialSpringVelocity: 10, options: [], animations: {
self.bounds = toView.bounds;
self.frame = toView.frame
self.backgroundColor = toView.backgroundColor
}, completion: nil)
}
making it super easy to use:
btnYes.morphToView(1.3, delay: 0.0, toView: dateSelector)
Thursday, 18 February 2016
Xamarin Android aapt.exe exited with code 1, Resources.deisgner.cs not regenerating
Wasted ages on this - Resources.deisgner.cs was not updating and eventually I was getting an error "Xamarin Android aapt.exe exited with code 1".
The solution turned out be simple - I'd added some images to my resources folder that contained hyphens in their filenames. I removes these, and everything started working again.
The solution turned out be simple - I'd added some images to my resources folder that contained hyphens in their filenames. I removes these, and everything started working again.
Xamarin Android detect Android version and perform circular reveal
Working on a simple circular reveal using Animator, I needed to detect if we were running >=Lollipop or not. This is how I did it. I'll probably refactor this somewhat but here's the headlines:
var _circle = FindViewById<imageview>(Resource.Id.imageView1);
var currentapiVersion = Android.OS.Build.VERSION.SdkInt;
if (currentapiVersion >= Android.OS.BuildVersionCodes.Lollipop)
{
// Do something for lollipop and above versions
// get the center for the clipping circle
int cx = _circle.Width / 2;
int cy = _circle.Height / 2;
// get the final radius for the clipping circle
var finalRadius = (float)Math.Sqrt(cx * cx + cy * cy);
// create the animator for this view (the start radius is zero)
Animator anim =
ViewAnimationUtils.CreateCircularReveal(_circle, cx, cy, 0, finalRadius);
// make the view visible and start the animation
_circle.Visibility = ViewStates.Visible;
anim.Start();
}
else
{
_circle.Visibility = ViewStates.Visible;
}
Xamarin C# equivalent of Math.hypot
I'm doing some more Xamarin for the next few weeks, and today I'm working on a material-design circular reveal for an Android app. I had to convert this line of Java (amongst others) into C#:
float finalRadius = (float)Math.hypot(cx, cy);
And...the answer is.....
var finalRadius = (float)Math.Sqrt(cx * cx + cy * cy);
Thursday, 28 January 2016
Building a row-based email template in Adestra MessageFocus Email Editor
I had the pleasure of using Adestra's new (still in beta, apparently) email editor this week, and it seemed to do everything we wanted. I inherited an HTML template with 10 different rows, and the brief was to allow the user to create an email using any number of any of these rows, in any order, with editable text, links images etc.
As an overview, if you wish to implement a typical row-based system you probably have the following html structure:
To use this in the Email Editor, where you can place any type of row wherever you want any number of times you need to use alternates and a single overall repeater of the same name, like so:
This creates the following type of experience in the Email Editor, allowing you to create/delete rows at will, and selecting which alternative you desire:

The following amf attributes create dynamic (editable) links, images, single text lines and text areas:
As an overview, if you wish to implement a typical row-based system you probably have the following html structure:
<table>
<!-- row type 1 here -->
</table>
<table>
<!-- row type 2 here -->
</table>
<table>
<!-- row type 3 here -->
</table>
<table>
<!-- row type 4 here -->
</table>
To use this in the Email Editor, where you can place any type of row wherever you want any number of times you need to use alternates and a single overall repeater of the same name, like so:
<table amf:alternate="row" amf:option="row_1" amf:repeat="row">
<!-- row type 1 here -->
</table>
<table amf:alternate="row" amf:option="row_2">
<!-- row type 2 here -->
</table>
<table amf:alternate="row" amf:option="row_3">
<!-- row type 3 here -->
</table>
<table amf:alternate="row" amf:option="row_4">
<!-- row type 4 here -->
</table>
This creates the following type of experience in the Email Editor, allowing you to create/delete rows at will, and selecting which alternative you desire:
The following amf attributes create dynamic (editable) links, images, single text lines and text areas:
<a href="www.mysite.com" amf:link="my_link">Go here</a>
<img src="/img/myimage.png" amf:image="image_1">
<span amf:textline="header_line">This is a single line</span>
<p amf:textbox="a_paragrpah_of_text">lots of text...</p>
Subscribe to:
Posts (Atom)