dotnet / dotnet/macios

UIAppearance appearanceWhenContainedInInstancesOfClasses incorrectly restricted to tvOS

Open
#3,230 3 comments 12 reactions 0 assignees View on GitHub
copilot-candidate enhancement good first issue iOS missing-api-bindings
Dominant language
C#
Stars
2.9k
Forks
576
Avg merge
2d 13h
Merged PRs (30d)
96

Description

Note: This is a C/P from my StackOverflow answer, so if you need additional info, just ask, thanks.

* https://stackoverflow.com/questions/48262588/xamarin-ios-uiapperance-setdefaulttextattributes

There are a *number* of missing `UIAppearance` features in Xamarin.iOS and in regards to your question, there is a *missing* API.

* This is a bug, 🍣 I wrote my own `UIAppearance.cs` to add the missing features and correct the missing API and *assume* no other Xamarin.iOS coders really use the newer `UIAppearance` features as it has been broken since iOS 9 in Xamarin.

First, `appearanceWhenContainedIn` is deprecated and you should be using `appearanceWhenContainedInInstancesOfClasses` instead.

>AppearanceWhenContainedIn - was deprecated in iOS 9 and is not recommended for use.

Second, `appearanceWhenContainedInInstancesOfClasses` is **incorrectly** defined within `Xamarin.iOS` as ***only available in `tvOS`*** via a `#if TVOS` and that is just not true.

Re: Apple Docs: https://developer.apple.com/documentation/uikit/uiappearance/1615013-appearancewhencontainedininstanc

#if TVOS
// new in iOS9 but the only option for tvOS
const string selAppearanceWhenContainedInInstancesOfClasses = "appearanceWhenContainedInInstancesOfClasses:";
~~~

[UIAppearance.cs#L77][1]

Thus it is not available via the iOS wrapper API, but of course is available directly from the ObjC runtime as such:

var NSForegroundColorAttributeName = Dlfcn.GetStringConstant(UIKitLibraryHandle, "NSForegroundColorAttributeName");
var defaultAttributes = NSDictionary.FromObjectsAndKeys(new NSObject[] { UIColor.Red }, new NSObject[] { NSForegroundColorAttributeName });
var styleHandle = GetAppearanceEx(Class.GetHandle("UITextField"), typeof(UISearchBar));
void_objc_msgSend_IntPtr(styleHandle, Selector.GetHandle("setDefaultTextAttributes:"), defaultAttributes.Handle);
var searchBar = new UISearchBar(new CGRect(0, 50, 300, 40));
searchBar.Placeholder = "Xamarin.iOS";
Add(searchBar);

[![enter image description here][2]][2]

The next problem there are a number of Xamarin.iOS methods marked **internal** that are needed for the above code to function, so some copy/paste/modify of some source is needed:

public const string selAppearanceWhenContainedInInstancesOfClasses = "appearanceWhenContainedInInstancesOfClasses:";

public static readonly IntPtr UIKitLibraryHandle = Dlfcn.dlopen("/System/Library/Frameworks/UIKit.framework/UIKit", 0);

[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
public static extern IntPtr IntPtr_objc_msgSend_IntPtr(IntPtr receiver, IntPtr selector, IntPtr arg1);

[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
public static extern void void_objc_msgSend_IntPtr(IntPtr receiver, IntPtr selector, IntPtr arg1);

public static IntPtr GetAppearanceEx(IntPtr class_ptr, params Type[] whenFoundIn)
{
var ptrs = TypesToPointers(whenFoundIn);
var handles = NSArray.FromIntPtrs(ptrs);
using (var array = handles)
{
return IntPtr_objc_msgSend_IntPtr(class_ptr, Selector.GetHandle(selAppearanceWhenContainedInInstancesOfClasses), array.Handle);
}
}

public static IntPtr[] TypesToPointers(Type[] whenFoundIn)
{
IntPtr[] ptrs = new IntPtr[whenFoundIn.Length];

for (int i = 0; i < whenFoundIn.Length; i++)
{
if (whenFoundIn[i] == null)
throw new ArgumentException(String.Format("Parameter {0} was null, must specify a valid type", i));
if (!typeof(NSObject).IsAssignableFrom(whenFoundIn[i]))
throw new ArgumentException(String.Format("Type {0} does not derive from NSObject", whenFoundIn[i]));

var classHandle = Class.GetHandle(whenFoundIn[i]);
if (classHandle == IntPtr.Zero)
throw new ArgumentException(string.Format("Could not find the Objective-C class for {0}", whenFoundIn[i].FullName));
ptrs[i] = classHandle;
}
return ptrs;
}

### Xamarin.iOS Version: 11.8.0.1

[1]: https://github.com/xamarin/xamarin-macios/blob/fc55e4306f79491fd269ca2495c6a859799cb1c6/src/UIKit/UIAppearance.cs#L77
[2]: https://i.stack.imgur.com/xYMJD.png

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.