Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make it possible to use IconicsDrawable to define xml drawable #481

Closed
dzamlo opened this issue Dec 25, 2019 · 6 comments
Closed

make it possible to use IconicsDrawable to define xml drawable #481

dzamlo opened this issue Dec 25, 2019 · 6 comments
Assignees
Milestone

Comments

@dzamlo
Copy link
Contributor

dzamlo commented Dec 25, 2019

Starting with API 24, you can define drawable in xmls that are implemented in code instead of being limited to the few existing drawable.

If IconicsDrawable supported that, you could create a drawable with this content (in res/drawable):

<?xml version="1.0" encoding="utf-8"?>
<com.mikepenz.iconics.IconicsDrawable xmlns:app="http://schemas.android.com/apk/res-auto"
    app:iiv_icon="gmd-favorite" />

And then, you could use it in a lot of place that need a drawable, including in your menu definition. This would replace most, if not all, use of IconicsMenuInflaterUtil for API >= 24.

There is three things that the Drawable needs to do for this to work:

  1. it need a no argument constructor
  2. it need to override public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme). This method will be called on the drawable instance. It's in this method that you get all the values from the XML.
  3. the attributes needs to be defined in attrs.xml

For IconicsDrawable, the issue is the need for the Context. We need a way to make it not need the context.
If I read the code correctly, it used for two things: initializing Iconics and for some of the setter.

I see two way of making the Context not mandatory:

  1. Making the context field nullable
    The Iconics.init(context) call will throw an exception, if Iconics.init was not called before: I thing this is what we want
    For all the setter that use the context: make them crash (use context!!). Provides an alternative that take the context as an argument. The problem is that we loose some safety

  2. Move all the code from IconicsDrawable to a new class (IconicsDrawableNoContext for example). Remove the context field. Call Iconics.init(null) instead of Iconics.init(context). Modify all the setters that use the context so that they take the context as a parameter.
    Make IconicsDrawable inherit from this new class. Implement all the setter that need the context by calling the version with the context in parameter. You could then use IconicsDrawableNoContext in the XMLs.

I prefer the second solution.

What do you think of all that?

@mikepenz mikepenz self-assigned this Dec 25, 2019
@mikepenz
Copy link
Owner

Thank you so much for this issue, I was not aware that this is possible, but looks absolutely like an amazing thing to introduce.

For the Context topic. Iconics actually already had a way to work without the context, this was disabled now as having an applicationContext to be used for something like resource creation is actually problematic as it may not contain all relevant values from the current theme. or from the config changes.
The context should always be as close to the views context as possible.

Sow e had this possibility via the provider: https://github.com/mikepenz/Android-Iconics/blob/develop/library-core/src/main/java/com/mikepenz/iconics/IconicsContentProvider.kt#L27

I wonder if there is a different way to get the context inside this drawable? how will it resolve colors for example if set as a theme references like ?colorPrimary?

Having a variant of the IconicsDrawable like a BaseIconicsDrawable sounds like a possibility. Or we have the Context field and the ctor but all usages of methods which require the Context are actually extension functions on the IconicsDrawable. (and throw an exception if no context is available) So the old API would still be the same, and you could always provide the Context if it is needed for resource resolution or so?

@dzamlo
Copy link
Contributor Author

dzamlo commented Jan 9, 2020

I wonder if there is a different way to get the context inside this drawable? how will it resolve colors for example if set as a theme references like ?colorPrimary?

My understanding is that you can resolve them using the argument to the inflate method (that Android magically call with the correct argument)

and throw an exception if no context is available
The advantage of splitting the class is that can guarantee at compile time that it wont happen. You can only call the method without an Context argument on an instance of the class that require a context.

I don't understand what making the method extension functions would change?

@dzamlo
Copy link
Contributor Author

dzamlo commented Jan 11, 2020

I made a quick-and-dirty proto to see what works or not (using the approach of making the context field nullable, as it is the simplest for a quick and dirty proto) (https://github.com/dzamlo/Android-Iconics branch drawable-from-xml-proto)

Regarding the theme attributes, you can't (always) resolve them in the inflate method. The theme argument is null. But later, the canApplyTheme method is called and if it return true, the applyTheme method is called:
https://cs.android.com/android/_/android/platform/frameworks/base/+/8cbdf944528e513293b1e5e738b2c16a525f9520:core/java/android/content/res/ResourcesImpl.java;l=671;drc=4487398e0dca180c0a3223cd23949861440702db

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/graphics/java/android/graphics/drawable/ColorDrawable.java seems to be a good example of how to handle that correctly

@mikepenz
Copy link
Owner

Thank you very much. I should have a chance later today to look at it and experiment with it too. Could you perhaps open a PR with it. So when we get it in that you'll get the contributors badge here.

Really appreciate your idea and effort

@mikepenz
Copy link
Owner

@dzamlo thanks for the initial changes. Which were already great to see how it is supposed to be used.
I was really not aware of this API possibility, but it is great and makes it really helpful.

So I actually figured it makes sense to bring this in v5 with a major refactor, removing context requirement for drawables altogether. and requiring resources and theme which is the same the inflate method offers.

You can see the current (initial) commit of this refactor here: #490 (based on top your initial changes)

I will continue this refactor in the coming days.

thank you so much again for the initial changes! It is amazing to finally be able to use iconics directly as drawable (even though if it is just API 24+)

@mikepenz mikepenz added this to the v5.0.0 milestone Jan 11, 2020
@mikepenz
Copy link
Owner

This is now supported in the first a01 of v5 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants