Fixing Button CornerRadius in .NET MAUI

Written by wdebruin | Published 2023/12/15
Tech Story Tags: .net | .net-maui | cornerradius-button | software-architecture | mobile-app-development | open-source-software | contributing-to-open-source | cross-platform-app-development

TLDRCornerRadius on Android buttons did not work when the radius was set to 0. I fixed the issue and wrote a device test.via the TL;DR App

This is the story of my first bugfix in .NET MAUI. As a software architect, I work with a group of great developers. Sometimes we run into issues with the frameworks that we depend on, such as .NET MAUI for our mobile applications. The trick is to not stop there. Aside from reporting them, we can try to fix those issues.

The issue

For one of our apps, we wanted to create buttons with 90-degree corners. So we set the CornerRadius to 0 in the XAML.

<Button
    CornerRadius="0"
    BackgroundColor="Purple"
    TextColor="White"
    Text="CornerRadius" />

For iOS this worked fine, the result for Android was surprising:

We have encountered a bug in .NET MAUI. Specifically in the control “Button”, for the platform Android.

In .NET MAUI there is a very nice pattern called the “Handler Architecture”.

  1. The code you write in the XAML is a “VirtualView” with a MAUI Control, Button in this case

  2. The Handler converts the “Button” to an Android “AppCompatButton”.

For many issues with controls, you can write workarounds by modifying or replacing the Handler behavior. That is possible because handlers define a mapping, between properties and the conversion to the native platform. You can configure this in your app startup.

In this case, the issue was with what happened with the CornerRadius property.

I decided not to write a workaround.

It was time to open the hood (or bonnet for the British 🙃).

Fixing the issue

To investigate, I cloned the .NET MAUI solution from https://github.com/dotnet/maui and followed the steps in the Development Guide to build and run it.

Using my knowledge of the handler pattern, I searched for CornerRadius in the Android Button Handler.

And sure enough, this check on CornerRadius is suspicious.

if (button.CornerRadius > 0)
    mauiDrawable.SetCornerRadius(button.CornerRadius);

So I set a breakpoint on this check and ran the Sandbox project in the MAUI solution with the Button with CornerRadius of 0. And indeed, this code is skipped, CornerRadius is not set! Then I changed this check to >= and ran again, and suddenly I had 90-degree corners!

Also, I noticed that the default CornerRadius is 6, so when it skips setting the radius to 0 it will be a rounded corner.

Opening a Pull Request

The next step was to open a Pull Request. These are the steps:

  1. Click on Fork and fork the MAUI project to my own Github
  2. Create a branch and commit the fix
  3. Go to Pull Requests in the MAUI Github and click on the suggestion to open a PR for the forked branch into the main.

I started to look for related issues and was able to connect three open issues about this problem to the PR.

Device tests: Running Unit Tests on an Android Phone

The reviewers suggested that a Device Test should be added. I got the nice comment that I should let them know if they made tests too weird 😀, they would be open for a call to help. I didn’t need that but it was nice that I got the offer for more collaboration.

A device test is a unit test that runs on the actual platform, in this case, Android. There is a Test Runner App that can run the unit tests. It looks like this on my phone:

If I tap “Run All Tests”, the processor goes up and the battery goes down 😆

Writing a test in this codebase was tricky, especially finding examples and getting the output CornerRadius from the handler. I used a Theory to run two tests, for radius of 0 and radius of 5. (XUnit)

  1. Arrange phase, I setup a button with a CornerRadius of 0.

  2. Act phase, I let the handler code execute and get two values:

    1. The ViewValue for CornerRadius, from the CrossPlatform View input

    2. The PlatformViewValue for CornerRadius, from the Handler output.

      In getting the PlatformViewValue I use reflection to get the private variable cornerRadius*,* which is used in OnDraw(). In the drawing of a Button the vector path of the border and its corners is calculated. It uses cornerRadius in the calculation.

  3. Assert phase, I check that the output value of the handler is identical to what I expect.

Conclusion

After committing this test the reviewers approved. It got merged into the main branch and I got a nice thank you. I am now a hungry contributor looking forward to an opportunity to fix another bug.

We as a community can make open-source work. For .NET MAUI the future is bright, in my opinion, the improvements are big between major .NET versions. If we help iron out the remaining issues that we encounter, this framework will be a big success.

Here you can find the Pull Request mentioned in this article:

https://github.com/dotnet/maui/pull/18959


Written by wdebruin | Dutch software development addict with .NET, Cloud and Mobile. In freetime a chess and tennis player
Published by HackerNoon on 2023/12/15