Implementation of Ripple effect from Material Design for Android API 9+

Overview

RippleEffect

RippleEffect

ExpandableLayout provides an easy way to create a view called header with an expandable view. Both view are external layout to allow a maximum of customization. You can find a sample that how to use an ExpandableLayout to your layout.

RippleEffect GIF

Integration

The lib is available on Maven Central, you can find it with Gradle, please

dependencies {
    compile 'com.github.traex.rippleeffect:library:1.3'
}

Usage

RippleView

Declare a RippleView inside your XML layout file with a content like an ImageView or whatever.

<com.andexert.library.RippleView
  android:id="@+id/more"
  android:layout_width="?android:actionBarSize"
  android:layout_height="?android:actionBarSize"
  android:layout_toLeftOf="@+id/more2"
  android:layout_margin="5dp"
  rv_centered="true">

  <ImageView
    android:layout_width="?android:actionBarSize"
    android:layout_height="?android:actionBarSize"
    android:src="@android:drawable/ic_menu_edit"
    android:layout_centerInParent="true"
    android:padding="10dp"
    android:background="@android:color/holo_blue_dark"/>

</com.andexert.library.RippleView>

If you want to know when the Ripple effect is finished, you can set a listener on your view

    rippleView.setOnRippleCompleteListener(new RippleView.OnRippleCompleteListener() {

        @Override
        public void onComplete(RippleView rippleView) {
            Log.d("Sample", "Ripple completed");
        }

    });

If you want to add an OnClickListener don't forget to add it to the RippleView like this:

    final RippleView rippleView = (RippleView) findViewById(R.id.rippleView);
    rippleView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //TODO: onRippleViewClick
        }
    });

Customization

You can change several attributes in the XML file, you have to remove "rv_" if you are using a version below v1.1.1 :

  • app:rv_alpha [integer def:90 0-255] --> Alpha of the ripple
  • app:rv_framerate [integer def:10] --> Frame rate of the ripple animation
  • app:rv_rippleDuration [integer def:400] --> Duration of the ripple animation
  • app:rv_ripplePadding [dimension def:0] --> Add a padding to the ripple
  • app:rv_color [color def:@android:color/white] --> Color of the ripple
  • app:rv_centered [boolean def:false] --> Center ripple in the child view
  • app:rv_type [enum (simpleRipple, doubleRipple) def:simpleRipple] --> Simple or double ripple
  • app:rv_zoom [boolean def:false] --> Enable zoom animation
  • app:rv_zoomDuration [integer def:150] --> Duration of zoom animation
  • app:rv_zoomScale [float def:1.03] --> Scale of zoom animation

For each attribute you can use getters and setters to change values dynamically.

Troubleshooting

If you want to use the double ripple you have to set a background for the RippleView or for its child.

Acknowledgements

Thanks to Google for its Material Design :)

MIT License

    The MIT License (MIT)

    Copyright (c) 2014 Robin Chutaux

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
Comments
  • Underflow in restore - more restores than saves : on Android M (6.0)

    Underflow in restore - more restores than saves : on Android M (6.0)

    09-09 08:42:48.592 13857 13857 E AndroidRuntime: java.lang.IllegalStateException: Underflow in restore - more restores than saves 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.graphics.Canvas.native_restore(Native Method) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.graphics.Canvas.restore(Canvas.java:540) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at com.andexert.library.RippleView.draw(RippleView.java:166) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.View.updateDisplayListIfDirty(View.java:15174) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.View.updateDisplayListIfDirty(View.java:15134) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.View.updateDisplayListIfDirty(View.java:15134) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.View.updateDisplayListIfDirty(View.java:15134) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.View.updateDisplayListIfDirty(View.java:15134) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.View.updateDisplayListIfDirty(View.java:15134) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.View.updateDisplayListIfDirty(View.java:15134) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.View.updateDisplayListIfDirty(View.java:15134) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.View.updateDisplayListIfDirty(View.java:15134) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.View.updateDisplayListIfDirty(View.java:15134) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:281) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:287) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:322) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewRootImpl.draw(ViewRootImpl.java:2615) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2434) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2067) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.Choreographer.doCallbacks(Choreographer.java:670) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.Choreographer.doFrame(Choreographer.java:606) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:739) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.os.Looper.loop(Looper.java:148) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5417) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 09-09 08:42:48.592 13857 13857 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

    opened by arsalancode 41
  • OnClick not fired

    OnClick not fired

    Hi Is anybody having problems setting OnClick listeners? I tried with the sample too, using standard way, using Butterknife. I tried to set the listener on the RippleView, or on the inner ImageView. I can't get the click fired. Thank you

    opened by hamen 22
  • Crash on Android 6.0 in RippleView.draw()

    Crash on Android 6.0 in RippleView.draw()

    Today I've installed Android 6.0 (release) and ripple is crashing, here is the stacktrace:

    E/AndroidRuntime: java.lang.IllegalStateException: Underflow in restore - more restores than saves E/AndroidRuntime: at android.graphics.Canvas.native_restore(Native Method) E/AndroidRuntime: at android.graphics.Canvas.restore(Canvas.java:540) E/AndroidRuntime: at com.andexert.library.RippleView.draw(RippleView.java:166)

    opened by emanzanoaxa 21
  • New error Marshmallow (only?) -

    New error Marshmallow (only?) - "Underflow in restore - more restores than saves"

    Error at:

    com.andexert.library.RippleView.draw (RippleView.java:166)

    Not sure if this helps? http://stackoverflow.com/questions/18220084/underflow-in-restore-in-android-4-3

    opened by conzorz 20
  • Onitemclicklistener not working on listview with this library

    Onitemclicklistener not working on listview with this library

    I used the same code as you used . Only difference is i used listview in place of recyclerview. I applied ripple widget to the list item that i inflated. I kept that ripple widget com.andexert.library.RippleView as parent(same as you did) in row_view.xml. By doing this ripples are applied well but on click listener of list view stopped working. Please help me how to resolve this

    opened by manpreetsinghsodhi 16
  • java.lang.IllegalStateException: Underflow in restore on Virtual Device

    java.lang.IllegalStateException: Underflow in restore on Virtual Device

    Is that normal if an IllegalStateException occurred when I ran it on the Genymotion Virtual Device ? Because it is OK on real Android Device.

    12-21 11:01:58.933 9458-9458/com.***.**** E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.***.****, PID: 9458
    java.lang.IllegalStateException: Underflow in restore - more restores than saves
        at android.graphics.Canvas.native_restore(Native Method)
        at android.graphics.Canvas.restore(Canvas.java:540)
        at com.andexert.library.RippleView.draw(RippleView.java:166)
        at android.view.View.updateDisplayListIfDirty(View.java:15174)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573)
        at android.view.View.updateDisplayListIfDirty(View.java:15134)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3593)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3573)
        at android.view.View.updateDisplayListIfDirty(View.java:15134)
        ......
    
    opened by WaylanPunch 12
  • Ripple event listener

    Ripple event listener

    Hi, first of all, I would like to say thanks for this lib (it is my favourite amongst other ripple libraries).

    However, I was wondering; is there any chance that you could add ripple event listeners (e.g. onRippleAnimationComplete), or custom onClick listeners, so that we wouldn't need to use delayed execution to display ripple first and then execute our code? Also, will there be any methods like "rippleStop" to stop ripple display?

    opened by dmacan23 10
  • RecyclerView problem

    RecyclerView problem

    Hello!

    First of all congrats for the library. I wanna know if there is any way of waiting until the ripple animation ends to then send the click event to the child view.

    I am asking it because I am trying to use it in a RecyclerView but it isn't possible to see it till the end.

    Cheers,

    opened by leonardossantos 5
  • Fixed crash on Android 6.0, caused by different number of calls to ca…

    Fixed crash on Android 6.0, caused by different number of calls to ca…

    …nvas.restore() / canvas.save(). This may be caused by new restrictions introduced to Marshmallow.

    Updated compile, target and support lib versions to 23.

    opened by emanzanoaxa 4
  • Can we start RippleEffect by click on another view ?

    Can we start RippleEffect by click on another view ?

    Hi, i tried to add this method to RippleView class:

    public void startRippleEffect() { this.x = getMeasuredWidth() / 2; this.y = getMeasuredHeight() / 2; this.animationRunning = true; invalidate(); }

    it works with me but at first, the user have to click the view at least one time :(

    what is the solution?

    opened by tarek360 4
  • Prevent Exception in Android Studio Layout View

    Prevent Exception in Android Studio Layout View

    Android Studio has problems rendering a layout where RippleView is present. You should avoid that by using View.isInEditMode() in your initmethod.

    Your init should look like:

    private void init(final Context context, final AttributeSet attrs)
        {
            if (!isInEditMode()) {
              final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RippleView);
              rippleColor = typedArray.getColor(R.styleable.RippleView_rv_color, getResources().getColor(R.color.rippelColor));
              rippleType = typedArray.getInt(R.styleable.RippleView_rv_type, 0);
    
              [...]
    
              this.setDrawingCacheEnabled(true);
            }
        }
    

    Since you don't need to show anything in the preview window it is enough to just do nothing when in edit mode.

    opened by dkunzler 4
  • java.lang.IllegalStateException: Underflow in restore - more restores than saves

    java.lang.IllegalStateException: Underflow in restore - more restores than saves

    机型:小米4c 系统版本 7.0

    java.lang.IllegalStateException: Underflow in restore - more restores than saves at android.graphics.Canvas.native_restore(Native Method) at android.graphics.Canvas.restore(Canvas.java:522) at com.andexert.library.RippleView.draw(RippleView.java:166) at android.view.View.updateDisplayListIfDirty(View.java:16078) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730) at android.view.View.updateDisplayListIfDirty(View.java:16041) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730) at android.view.View.updateDisplayListIfDirty(View.java:16041) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730) at android.view.View.updateDisplayListIfDirty(View.java:16041) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730) at android.view.View.updateDisplayListIfDirty(View.java:16041) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730) at android.view.View.updateDisplayListIfDirty(View.java:16041) at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730) at android.view.View.updateDisplayListIfDirty(View.java:16041) at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:657) at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:663) at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:771) at android.view.ViewRootImpl.draw(ViewRootImpl.java:2833) at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2641) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2248) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1283) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6359) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:873) at android.view.Choreographer.doCallbacks(Choreographer.java:685) at android.view.Choreographer.doFrame(Choreographer.java:621) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:859) at android.os.Handler.handleCallback(Handler.java:754) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:163) at android.app.ActivityThread.main(ActivityThread.java:6342) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:880) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:770)

    opened by TengJW 4
  • Start animation programatically and multi-touch same item multiple times

    Start animation programatically and multi-touch same item multiple times

    Hello!

    How would I go about clicking a button really fast? It seems that this is not possible, let's say I want to click it 5 times in a second; I won't be able because of the animation. How can I manage it?

    Also, is it possible to start an animation of one of the RippleView programatically, without clicking the actual button?

    Thanks!

    opened by tommyzat 0
Owner
Robin Chutaux
Robin Chutaux
Ripple effect for Android 14+

RippleDrawable Port of Android <ripple> effect for pre lollipop devices with android 14 + (ICS+) (well, since NineOldAndroids is deprecated, this libr

Ozodrukh 516 Nov 25, 2022
Material Design implementation for Android 4.0+. Shadows, ripples, vectors, fonts, animations, widgets, rounded corners and more.

Carbon Material Design implementation for Android 4.0 and newer. This is not the exact copy of the Lollipop's API and features. It's a custom implemen

null 3k Jan 9, 2023
Custom drawer implementation for Material design apps.

material-drawer Custom drawer implementation for Material design apps. Demo A demo app is available on Google Play: Screenshots Fixed items Select pro

Jan Heinrich Reimer 600 Nov 18, 2022
Default colors and dimens per Material Design guidelines and Android Design guidelines inside one library.

Material Design Dimens Default colors and dimens per Material Design guidelines and Android Design guidelines inside one library. Dimens Pattern: R.di

Dmitry Malkovich 1.4k Jan 3, 2023
A Gmail-like Material Drawer implementation

AdvancedMaterialDrawer A Gmail-like Material Drawer implementation Based on neokree's MaterialDrawer library, but they are not the same. I have made m

Marc Schäfers 200 Oct 27, 2022
A library to bring fully animated Material Design components to pre-Lolipop Android.

Material MaterialLibrary is an Open Source Android library that back-port Material Design components to pre-Lolipop Android. MaterialLibrary's origina

Rey Pham 6k Dec 21, 2022
The flexible, easy to use, all in one drawer library for your Android project. Now brand new with material 2 design.

MaterialDrawer ... the flexible, easy to use, all in one drawer library for your Android project. What's included ?? • Setup ??️ • Migration Guide ??

Mike Penz 11.6k Dec 27, 2022
Floating Action Button for Android based on Material Design specification

FloatingActionButton Yet another library for drawing Material Design promoted actions. Features Support for normal 56dp and mini 40dp buttons. Customi

Zendesk 6.4k Dec 26, 2022
Android drawer icon with material design animation

LDrawer Android drawer icon with material design animation Note Basically same as appcompat_v7 version 21, you can use appcompat_v7 compile 'com.andro

Hasan Keklik 1.4k Dec 25, 2022
[] Android Library that implements Snackbars from Google's Material Design documentation.

DEPRECATED This lib is deprecated in favor of Google's Design Support Library which includes a Snackbar and is no longer being developed. Thanks for a

null 1.5k Dec 16, 2022
Android Sample Project with Material Design and Toolbar.

AndroidMaterialDesignToolbar -- PROJECT IS NOT SUPPORTED Android Sample Project with Material Design and Toolbar. Project use Appcompat library for ma

kemal selim tekinarslan 713 Nov 11, 2022
Android drawer icon with material design animation

LDrawer Android drawer icon with material design animation Note Basically same as appcompat_v7 version 21, you can use appcompat_v7 compile 'com.andro

Hasan Keklik 1.4k Dec 25, 2022
Floating Action Button for Android based on Material Design specification

FloatingActionButton Yet another library for drawing Material Design promoted actions. Features Support for normal 56dp and mini 40dp buttons. Customi

Zendesk 6.4k Jan 3, 2023
A library support form with material design, construct same with Android UI Framework

SwingUI A slight Java Swing library support form with material design, construct same with Android UI Framework writen in Kotlin Supported: 1. Screen:

Cuong V. Nguyen 3 Jul 20, 2021
Android Material Design Components

Android-Material-Design-Components Material design is a comprehensive guide for visual, motion, and interaction design across platforms and devices. G

Velmurugan Murugesan 3 Jun 10, 2022
Modular and customizable Material Design UI components for Android

Material Components for Android Material Components for Android (MDC-Android) help developers execute Material Design. Developed by a core team of eng

Material Components 14.4k Dec 31, 2022
Easy creation and management of toggle buttons on Android from the Material Design spec.

ToggleButtonLayout Easy creation and management of toggle buttons from the Material Design spec. Read more about ToggleButtonLayout in our blog post.

Savvy 229 Jan 9, 2023
A gradle plugin that generates Material Design 3 theme for Android projects.

Same as Google's Material Theme Builder, but as a gradle plugin.

Rikka apps 41 Dec 6, 2022
Material Design icons by Google

Material design icons Material design icons is the official icon set from Google. The icons are designed under the material design guidelines. 4.0.0 U

Google 47.1k Jan 9, 2023