AnnotationSpan / Rialto / Spans / Text

Rialto: V1.1.0

Rialto is a new Android text styling library based upon Annotation Spans. Rialto enables you to provide consistent text formatting throughout your app by using annotations in your string resources. Previously we have looked at how to use Rialto, and I am extremely please to release Rialto 1.1.0 which contains some (hopefully!) useful new features.

Although Rialto is pretty easy to set up, it does need to be set up in each individual Activity. While this would not be so much of a problem for apps which have different visual styles for each Activity, but in many cases there will be certain annotations which would be useful to have available throughout the app. For this reason, V1.1.0 introduces a cascading Registry. The Rialto Registry is where all of the span factories are registered, and it is now possible to define a Registry within your Application instance. Any span factories that are registered directly to this Registry will be available to all of your Rialto Activities. You can register further span factories within each Activity, but these additions will only be available within the Activity itself. This provides great flexibility because you can define any common styles at application level, and then Activity-specific styles locally. Creating an Application Registry is pretty simple. You can either subclass RialtoApplication and register your global spans in onCreate():

class KotlinApplication : RialtoApplication() {

    override fun onCreate() {
        super.onCreate()
        registerSpanFactory("format", "underline") { UnderlineSpan() }
    }
}

Alternatively, if you would prefer not to subclass RialtoApplication, you can implement things manually with just a few additional lines of code:

class KotlinApplication @JvmOverloads constructor(
    registry: RialtoRegistry = Registry()
) : Application(), RialtoRegistry by registry {

    override fun onCreate() {
        super.onCreate()
        registerSpanFactory("format", "underline") { UnderlineSpan() }
    }
}

Kotlin delegation makes this really easy.

If you are doing this from Java, then it is slightly more work still, but still nothing major – you just need to perform the delegation manually:

public class JavaApplication extends Application implements RialtoRegistry {

    private RialtoRegistry delegate = new Registry();

    @NotNull
    @Override
    public Set<Function0<Object>> get(@NotNull String key, @NotNull String value) {
        return delegate.get(key, value);
    }

    @Override
    public void registerSpanFactory(@NotNull String key, @NotNull String value, @NotNull Function0<?> creator) {
        delegate.registerSpanFactory(key, value, creator);
    }

    @NotNull
    @Override
    public RialtoRegistry copy() {
        return delegate.copy();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        registerSpanFactory("format", "underline", UnderlineSpan::new);
    }
}

By doing this, any Activities which use Rialto will automatically get any span registrations that are made here – there’s nothing more that you need to do!

Currently it isn’t possible to do this selectively for specific Activities – if you have an Application-level Registry, then all Activities will get it. If anyone needs this functionality please raise an issue and I’ll look at adding an option to do this.

The other new feature introduced in Rialto 1.1.0 is the ability to load formatted strings containing annotations. Android only permits resource string formatting to be performed on simple string resources, so if you attempt to load a formatted String which contains annotations, then the annotations will be lost as it is loaded. Rialto 1.1.0 introduces an extension function to Resources which enables string resources containing formatting to be loaded as Spanned objects keeping the annotation spans intact. Rialto can then process these as normal.

If we have the following string resource defined:

<string name="formatted">This is a <annotation format="bold">%1$s</annotation> string</string>

This can be retrieved using the extension function with a set of format arguments which will be substituted in:

val newText = resources.getFormattedText(R.string.formatted, "formatted")

This takes the resource ID of the string and a varargs array of the values to use for the formatting. This works in the same way as Resources.getString(int id, Object… formatArgs) except that it returns a CharSequence with the annotations intact.

The following string will be produced:

This is a formatted string

The annotation span will remain, and will have expanded so that it now surrounds the word “formatted” which was substituted in as part of the formatting. Provided that we have a span factory registered for the key ‘format’ and value ‘bold’ to match the annotation in the string resource, then Rialto will correctly format things:

One limitation here is that annotations are only supported on the string resource itself. In other words they can be used in the string resource referenced by the first argument, but they cannot be used within any of the varargs parameters. Despite this limitation, this feature still provides some quite useful formatting of annotated strings.

That covers the new features in V1.1.0. Rialto is available on JCenter, and examples can be found in the GitHub repo.

© 2018, Mark Allison. All rights reserved.

Copyright © 2018 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.