🛠️ The missing drawable toolbox for Android. Create drawables programmatically and get rid of the boring and always repeated drawable.xml files.

Overview

DrawableToolbox

gitHub release platform license Awesome Kotlin Badge

English | 中文

The missing DrawableToolbox for Android. Create drawables programmatically and get rid of the boring and always repeated drawable.xml files.


Features

  • Create drawables programmatically
  • Support <shape>, <rotate>, <scale>, <ripple>, <layer-list> drawables
  • Support 'flip' (vertical or horizontal)

Contribute

Gradle

dependencies {
    implementation 'com.github.duanhong169:drawabletoolbox:${latestVersion}'
    ...
}

Replace ${latestVersion} with the latest version code. See releases.

Usage

Use the DrawableBuilder to setup the Drawable and call build() to create it.

Please check all the supported APIs in DrawableBuilder.kt.

Here are some examples:

Code:

DrawableBuilder()
        .rectangle()
        .hairlineBordered()
        .strokeColor(COLOR_DEFAULT)
        .strokeColorPressed(COLOR_PRESSED)
        .ripple()
        .build()

Result:

Bordered with Ripple

Code:

DrawableBuilder()
        .rectangle()
        .hairlineBordered()
        .mediumDashed()
        .strokeColor(COLOR_DEFAULT)
        .strokeColorPressed(COLOR_PRESSED)
        .ripple()
        .build()

Result:

Medium-dashed, Bordered with Ripple

Code:

DrawableBuilder()
        .rectangle()
        .rounded()
        .solidColor(COLOR_DEFAULT)
        .solidColorPressed(COLOR_PRESSED)
        .build()

Result:

Rounded, Filled with States

Code:

DrawableBuilder()
        .rectangle()
        .hairlineBordered()
        .longDashed()
        .rounded()
        .strokeColor(COLOR_DEFAULT)
        .strokeColorPressed(COLOR_PRESSED)
        .ripple()
        .build()

Result:

Rounded, Long-dashed, Bordered with Ripple

Code:

DrawableBuilder()
        .rectangle()
        .rounded()
        .gradient()
        .linearGradient()
        .angle(90)
        .startColor(COLOR_DEFAULT)
        .endColor(ContextCompat.getColor(context, R.color.colorPrimaryDark))
        .ripple()
        .rippleColor(COLOR_PRESSED)
        .build()

Result:

Rounded, Gradient with Ripple

Code:

val baseBuilder = DrawableBuilder()
        .rectangle()
        .rounded()
        .gradient()
        .gradientType(GradientDrawable.LINEAR_GRADIENT)
        .angle(90)
val normalState = baseBuilder
        .startColor(COLOR_DEFAULT)
        .endColor(ContextCompat.getColor(context, R.color.colorPrimaryDark))
        .build()
val pressedState = baseBuilder
        .startColor(COLOR_PRESSED)
        .endColor(ContextCompat.getColor(context, R.color.colorAccentDark))
        .build()

StateListDrawableBuilder()
        .normal(normalState)
        .pressed(pressedState)
        .build()

Result:

Rounded, Gradient with States

Code:

val baseBuilder = DrawableBuilder()
        .rectangle()
        .rounded()
        .hairlineBordered()
        .strokeColor(COLOR_DEFAULT)
        .solidColorSelected(COLOR_DEFAULT)
        .ripple()

return when(type) {
    SegmentedControlDrawableSpec.TYPE_LEFT_MOST -> {
        baseBuilder.topRightRadius(0)
                .bottomRightRadius(0)
                .build()
    }
    SegmentedControlDrawableSpec.TYPE_RIGHT_MOST -> {
        baseBuilder.topLeftRadius(0)
                .bottomLeftRadius(0)
                .build()
    }
    else -> {
        baseBuilder.cornerRadius(0).build()
    }
}

Result:

Segmented Control

Code:

val layer1 = DrawableBuilder()
        .size(200)
        .rectangle()
        .rounded()
        .hairlineBordered()
        .strokeColor(COLOR_DEFAULT)
        .strokeColorPressed(COLOR_PRESSED)
        .build()
val layer2 = DrawableBuilder()
        .rectangle()
        .rounded()
        .solidColor(COLOR_DEFAULT)
        .build()
val layer3 = DrawableBuilder()
        .rectangle()
        .rounded()
        .solidColor(Color.WHITE)
        .ripple()
        .rippleColor(COLOR_DEFAULT)
        .build()
LayerDrawableBuilder()
        .add(layer1)
        .add(layer2)
        .inset(10)
        .add(layer3)
        .inset(20)
        .build()

Result:

Layer List: Several Borders

Code:

val layer1 = DrawableBuilder()
        .size(180)
        .rectangle()
        .build()
val layer2 = DrawableBuilder()
        .oval()
        .solidColor(COLOR_DEFAULT)
        .build()
val layer3 = DrawableBuilder()
        .rectangle()
        .solidColor(COLOR_DEFAULT_DARK)
        .rotate(45f)
        .build()
val layer4 = DrawableBuilder()
        .rectangle()
        .bottomLeftRadius(100)
        .solidColor(COLOR_DEFAULT_DARK)
        .build()
val layer5 = DrawableBuilder()
        .oval()
        .solidColor(COLOR_DEFAULT)
        .build()
val layerDrawable = LayerDrawableBuilder()
        .add(layer1)
        .add(layer2)
        .inset(20, 20, 100, 100)
        .add(layer3)
        .inset(100, 20, 20, 100)
        .add(layer4)
        .inset(20, 100, 100, 20)
        .add(layer5)
        .inset(100, 100, 20, 20)
        .build()
DrawableBuilder()
        .baseDrawable(layerDrawable)
        .rotate(0f, 360f)
        .build()

Result:

Showcase: Layer List 1

Code:

// Rotate & Leveled the Ring
DrawableBuilder()
        .size(200)
        .ring()
        .useLevelForRing()
        .solidColor(COLOR_DEFAULT)
        .innerRadiusRatio(3f)
        .thicknessRatio(10f)
        .rotate(0f, 720f)
        .build()

Result:

Rotate & Leveled the Ring

Code:

// Rotate, Sweep & Flip the Ring
DrawableBuilder()
        .size(200)
        .ring()
        .innerRadiusRatio(3f)
        .thicknessRatio(10f)
        .gradient()
        .sweepGradient()
        .rotate(0f, 360f)
        .flip()
        .build()

Result:

Rotate, Sweep & Flip the Ring

Code:

// Rotate, Sweep & Scale the Oval with States
val baseBuilder = DrawableBuilder()
        .size(400)
        .oval()
        .gradient()
        .sweepGradient()
        .rotate(0f, 360f)
        .scale(0.5f)
        .scaleGravity(Gravity.START or Gravity.TOP)
val normalState = baseBuilder.build()
val pressedState = baseBuilder
        .startColor(COLOR_PRESSED)
        .endColor(0x7FFFFFFF)
        .build()
StateListDrawableBuilder()
        .normal(normalState)
        .pressed(pressedState)
        .build()

Result:

Rotate, Sweep & Scale the Oval with States

Please check out the app sample code SampleCodeSnippets.kt for more details.

License

Copyright 2018 Hong Duan

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  •     java.lang.NullPointerException: Attempt to invoke virtual method 'android.graphics.drawable.Drawable$ConstantState android.graphics.drawable.Drawable.getConstantState()' on a null object reference

    java.lang.NullPointerException: Attempt to invoke virtual method 'android.graphics.drawable.Drawable$ConstantState android.graphics.drawable.Drawable.getConstantState()' on a null object reference

    java.lang.NullPointerException: Attempt to invoke virtual method 'android.graphics.drawable.Drawable$ConstantState android.graphics.drawable.Drawable.getConstantState()' on a null object reference
            at android.graphics.drawable.RotateDrawable$RotateState.canConstantState(RotateDrawable.java:598)
            at android.graphics.drawable.RotateDrawable.getConstantState(RotateDrawable.java:398)
            at top.defaults.drawabletoolbox.CompatibleKt.setDrawable(Compatible.kt:173)
            at top.defaults.drawabletoolbox.RotateDrawableBuilder.build(RotateDrawableBuilder.kt:21)
            at top.defaults.drawabletoolbox.DrawableBuilder.wrapRotateIfNeeded(DrawableBuilder.kt:368)
            at top.defaults.drawabletoolbox.DrawableBuilder.access$wrapRotateIfNeeded(DrawableBuilder.kt:11)
            at top.defaults.drawabletoolbox.DrawableBuilder$wrap$1.invoke(DrawableBuilder.kt:329)
            at top.defaults.drawabletoolbox.DrawableBuilder$wrap$1.invoke(DrawableBuilder.kt:11)
            at top.defaults.drawabletoolbox.DrawableBuilder.wrap(DrawableBuilder.kt:336)
            at top.defaults.drawabletoolbox.DrawableBuilder.build(DrawableBuilder.kt:171)
            at top.defaults.drawabletoolboxapp.SampleCodeSnippetsKt$samples$11.build(SampleCodeSnippets.kt:183)
            at top.defaults.drawabletoolboxapp.DrawableFactory$DefaultImpls.build(DrawableFactory.kt:8)
            at top.defaults.drawabletoolboxapp.SampleCodeSnippetsKt$samples$11.build(SampleCodeSnippets.kt:173)
            at top.defaults.drawabletoolboxapp.spec.DrawableSpec.build(DrawableSpec.kt:8)
            at top.defaults.drawabletoolboxapp.spec.DrawableSpec.build$default(DrawableSpec.kt:8)
            at top.defaults.drawabletoolboxapp.DrawableSpecAdapter$ViewHolder.bind(DrawableSpecAdapter.kt:78)
            at top.defaults.drawabletoolboxapp.DrawableSpecAdapter.onBindViewHolder(DrawableSpecAdapter.kt:27)
            at top.defaults.drawabletoolboxapp.DrawableSpecAdapter.onBindViewHolder(DrawableSpecAdapter.kt:17)
            at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6781)
            at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6823)
            at android.support.v7.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5752)
            at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6019)
            at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
            at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
            at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
            at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1557)
            at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
            at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
            at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
            at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3641)
            at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:4194)
            at android.view.View.layout(View.java:16009)
            at android.view.ViewGroup.layout(ViewGroup.java:5181)
            at android.support.constraint.ConstraintLayout.onLayout(ConstraintLayout.java:1858)
            at android.view.View.layout(View.java:16009)
            at android.view.ViewGroup.layout(ViewGroup.java:5181)
            at android.widget.FrameLayout.layoutChildren(FrameLayout.java:639)
            at android.widget.FrameLayout.onLayout(FrameLayout.java:574)
            at android.view.View.layout(View.java:16009)
            at android.view.ViewGroup.layout(ViewGroup.java:5181)
            at android.support.v7.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:444)
            at android.view.View.layout(View.java:16009)
            at android.view.ViewGroup.layout(ViewGroup.java:5181)
            at android.widget.FrameLayout.layoutChildren(FrameLayout.java:639)
            at android.widget.FrameLayout.onLayout(FrameLayout.java:574)
            at android.view.View.layout(View.java:16009)
            at android.view.ViewGroup.layout(ViewGroup.java:5181)
    
    bug good first issue 
    opened by W-quan 6
  • Some features not working

    Some features not working

    First of all, rotate is not working in any situation.

    Secondly, baseDrawable not working as expected Suppose there is a drawable d1. It has solid color red And i am creating another drawable d2 based on d1. What i did is i used baseDrawable to make the d1 base of d2. I set solidColorPressed blue to d2. Now i am expecting d2 as red but blue on pressed. But it does not happens. Red in normal is working but blue in pressed not happens.

    So, am i expecting wrong or what happens to baseDrawble or what is the exact behaviour of baseDrawable.

    Also I tried to run your sample app but it crashed every times. Here is the log 2021-04-25 20:15:56.368 18279-18279/top.defaults.drawabletoolboxapp A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xaef010100 in tid 18279 (wabletoolboxapp), pid 18279 (wabletoolboxapp)

    opened by debduttapanda 0
  • Strange stroke behavior

    Strange stroke behavior

    Very strange showing on Android of a stroke with corners. Take a look on top right and bottom right corners This is code:

    val bgFormInputError = DrawableBuilder()
            .cornerRadius(16)
            .solidColor(bgColor)
            .strokeColor(strokeBgColor)
            .strokeWidth(2)
            .build()
    

    изображение

    opened by achatina 2
  • No field mGradientRadius in class Landroid/graphics/drawable/GradientDrawable$GradientState;

    No field mGradientRadius in class Landroid/graphics/drawable/GradientDrawable$GradientState;

    W: Accessing hidden field Landroid/graphics/drawable/GradientDrawable$GradientState;->mGradientRadius:F (dark greylist, reflection) W: java.lang.NoSuchFieldException: No field mGradientRadius in class Landroid/graphics/drawable/GradientDrawable$GradientState; (declaration of 'android.graphics.drawable.GradientDrawable$GradientState' appears in /system/framework/framework.jar) W: at java.lang.Class.getDeclaredField(Native Method) W: at top.defaults.drawabletoolbox.a.a(Compatible.kt:33) W: at top.defaults.drawabletoolbox.a.a(Compatible.kt:147) W: at top.defaults.drawabletoolbox.DrawableBuilder.a(DrawableBuilder.kt:307) W: at top.defaults.drawabletoolbox.DrawableBuilder.a(DrawableBuilder.kt:187) W: at b.b.a.a.b.a(DrawableUtil.kt:87) W: at com.wwyy.wzhxl.ui.main.recommend.AdapterRecommend.a(AdapterRecommend.kt:999) W: at com.wwyy.wzhxl.ui.main.recommend.AdapterRecommend.b(AdapterRecommend.kt:804) W: at com.zjw.des.base.BaseAdapter.a(BaseAdapter.kt:51) W: at com.zjw.des.base.BaseAdapter.onBindViewHolder(BaseAdapter.kt:41) W: at com.zjw.des.base.BaseAdapter.onBindViewHolder(BaseAdapter.kt:10) W: at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7065) W: at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7107) W: at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6012) W: at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6279) W: at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:288) W: at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:345) W: at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:361) W: at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:368) W: at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:399) W: at android.os.Handler.handleCallback(Handler.java:873) W: at android.os.Handler.dispatchMessage(Handler.java:99) W: at android.os.Looper.loop(Looper.java:226) W: at android.app.ActivityThread.main(ActivityThread.java:7225) W: at java.lang.reflect.Method.invoke(Native Method) W: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:499) W: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:962)

    opened by BarretWu 0
  • Added gitignore and annotations to the DrawableBuilder.kt. Removed the .idea folder

    Added gitignore and annotations to the DrawableBuilder.kt. Removed the .idea folder

    • Added annotations to the DrawableBuilder.kt for better interaction with the constructor.
    • The .idea folder did not contain any necessary files and can be deleted.
    opened by TalbotGooday 0
Releases(1.0.7)
Owner
Hong Duan
To be a better man. Focus on Android development.
Hong Duan
DSL for constructing the drawables in Kotlin instead of in XML

Android Drawable Kotlin DSL DSL for constructing the drawables in Kotlin instead of in XML Examples Shape drawables <?xml version="1.0" encoding="utf-

Infotech Group 178 Dec 4, 2022
Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders

Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Vehement 8 Nov 26, 2022
With Viola android face detection library, you can detect faces in a bitmap, crop faces using predefined algorithm and get additional information from the detected faces.

Viola Viola android face detection library detects faces automatically from a bitmap, crop faces using the predefined algorithms, and provides supplem

Darwin Francis 58 Nov 1, 2022
A flutter plugin to scan stripe readers and connect to the them and get the payment methods.

stripe_terminal A flutter plugin to scan stripe readers and connect to the them and get the payment methods. Installation Android No Configuration nee

Aawaz Gyawali 8 Dec 29, 2022
[Android Library] Get easy access to device information super fast, real quick

DeviceInfo-Sample Simple, single class wrapper to get device information from an android device. This library provides an easy way to access all the d

Anitaa Murthy 193 Nov 20, 2022
It's finally easy to take photos/videos via camera or get photos/videos from gallery on Android.

Shutter-Android It's finally easy to take photos/videos via camera or get photos/videos from gallery on Android. What is Shutter? Shutter is an Androi

Levi Bostian 56 Oct 3, 2022
KaMP Kit by Touchlab is a collection of code and tools designed to get your mobile team started quickly with Kotlin Multiplatform.

KaMP Kit Welcome to the KaMP Kit! About Goal The goal of the KaMP Kit is to facilitate your evaluation of Kotlin Multiplatform (aka KMP). It is a coll

Touchlab 1.7k Jan 3, 2023
Aarón Calixto Andrade 0 Dec 27, 2021
A nice weather that helps you get all information including: current weather, hourly weather and also forecasts for 16 days

WeatherForecast This is an ongoing project where I fetch all the weather data using Retrofit and Kotlin Coroutines over two APIs containing both curre

null 2 Jul 26, 2022
Simple MVVM app to get photos through https://unsplash.com api

MyPhotoLoaderApp Simple photo loading app powered by Unsplash.com which implements MVVM architecture using Hilt, Navigation Component, Retrofit, Pagin

Behnam Banaei 10 Oct 6, 2022
Example mod with Mixin to help you to get started with creating a mod with mixins.

ExampleMixinMod Example mod with Mixin to help you to get started with creating a mod with mixins. For usage of mixins, see here. Also, remember to tu

null 0 Dec 16, 2021
A set of highly-opinionated, batteries-included gradle plugins to get you started building delicious multi-module Kotlin projects

Sourdough Gradle What is Sourdough Gradle? Sourdough is a set of highly opinionated gradle plugins that aim to act as the starter for your Kotlin proj

Backbone 0 Oct 3, 2022
Simple Design for Kotlin bridge with Javascript. Also can get javascript console.log.

SDBridgeJava is here. If your h5 partner confused about how to deal with iOS and Android. This Demo maybe help. bilibili video introduction is here. Y

null 14 Dec 19, 2022
Android project setup files when developing apps from scratch. The codebase uses lates jetpack libraries and MVVM repository architecture for setting up high performance apps

Android architecture app Includes the following Android Respository architecture MVVM Jepack libraries Carousel view Kotlin Kotlin Flow and Livedata P

null 2 Mar 31, 2022
This server uses json files to model items, entities and more.

Design Server | Simple server to design items, entities or more About this project/server: This server uses json files to model items, entities and mo

Phillipp Glanz 5 Jan 7, 2022
Kotlin and Java API for generating .swift source files.

SwiftPoet SwiftPoet is a Kotlin and Java API for generating .swift source files. Source file generation can be useful when doing things such as annota

Outfox 232 Jan 2, 2023
Curations and configuration files for the OSS Review Toolkit.

ORT Config This repository contains configuration files for the OSS Review Toolkit. Content Curations The curations directory contains package curatio

OSS Review Toolkit 9 Dec 8, 2022
Sync Kotlin files with an Xcode project

Kotlin Xcode Sync Note Soon to be deprecated. You can add folder references instead. See here. Import kotlin files into an Xcode project. This is used

null 25 May 20, 2022
Astha Nayak 4 Oct 10, 2022