GithubHelp home page GithubHelp logo

skydoves / colorpicker-compose Goto Github PK

View Code? Open in Web Editor NEW
440.0 5.0 42.0 58.87 MB

๐ŸŽจ Kotlin Multiplatform color picker library for getting colors from any images by tapping on the desired color.

License: Apache License 2.0

Kotlin 99.24% Swift 0.76%
android jetpack-compose compose color-picker colorpicker skydoves

colorpicker-compose's Introduction

colorpicker-compose

Google
License API API Android Weekly Profile


๐ŸŽจ Kotlin Multiplatform color picker library that allows you to get colors from any images like gallery pictures by tapping on the desired color. Also, it supports brightness and alpha slider, which can adjust your ARGB factors.

Preview

Download

Maven Central

Version Catalog

If you're using Version Catalog, you can configure the dependency by adding it to your libs.versions.toml file as follows:

[versions]
#...
colorpicker = "1.1.1"

[libraries]
#...
compose-colorpicker = { module = "com.github.skydoves:colorpicker-compose", version.ref = "colorpicker" }

Gradle

Add the dependency below to your module's build.gradle.kts file:

dependencies {
    implementation("com.github.skydoves:colorpicker-compose:1.1.1")
    
    // if you're using Version Catalog
    implementation(libs.compose.colorpicker)
}

For Kotlin Multiplatform, add the dependency below to your module's build.gradle.kts file:

sourceSets {
    commonMain.dependencies {
        implementation("com.github.skydoves:colorpicker-compose:$version")
    }
}

Usage

First, you should initialize ColorPickerController, which allows you to control color pickers and all subcomponents.

val controller = rememberColorPickerController()

Next, you can implement a color picker with the ImageColorPicker composable function.

ImageColorPicker(
    modifier = Modifier.fillMaxSize(),
    paletteImageBitmap = ImageBitmap.imageResource(R.drawable.palettebar),
    controller = controller
)

ImageColorPicker

ImageColorPicker allows you to get colors from any images such as gallery pictures or drawable resources by tapping on the desired color. It interacts with the ColorPickerController to control the color picker and other components. You can use the ImageColorPicker as the following example:

ImageColorPicker(
    modifier = Modifier
        .fillMaxWidth()
        .height(450.dp)
        .padding(10.dp),
    controller = controller,
    paletteImageBitmap = ImageBitmap.imageResource(R.drawable.palettebar),
    paletteContentScale = PaletteContentScale.FIT,
    onColorChanged = { colorEnvelope: ColorEnvelope ->
        // do something
    }
)

With the modernstorage's Photo Picker, you can set an desired image as the palette like the below:

val context = LocalContext.current
val photoPicker =
    rememberLauncherForActivityResult(PhotoPicker()) { uris ->
        val uri = uris.firstOrNull() ?: return@rememberLauncherForActivityResult

        val bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            ImageDecoder.decodeBitmap(ImageDecoder.createSource(context.contentResolver, uri))
        } else {
            MediaStore.Images.Media.getBitmap(context.contentResolver, uri)
        }

        controller.setPaletteImageBitmap(bitmap.asImageBitmap())
    }

As you can see the above, you can set the palette with the setPaletteImageBitmap function of the controller.

PaletteContentScale

You can adjust your palette's image scale with the setPaletteContentScale function of the controller as the below:

controller.setPaletteContentScale(PaletteContentScale.FIT) // scale the image to fit width and height.
controller.setPaletteContentScale(PaletteContentScale.CROP) // center crop the image.

HsvColorPicker

HsvColorPicker allows you to get colors from HSV color palette by tapping on the desired color. It interacts with the ColorPickerController to control the color picker and other components. You can use the HsvColorPicker as the following example:

HsvColorPicker(
    modifier = Modifier
        .fillMaxWidth()
        .height(450.dp)
        .padding(10.dp),
    controller = controller,
    onColorChanged = { colorEnvelope: ColorEnvelope ->
        // do something
    }
)

To initialize the color picker with a specific color, pass the color to the initialColor argument. Initial color is white by default.

Note: If you use HsvColorPicker, you can not set the palette and content scale with the setPaletteImageBitmap and setPaletteContentScale functions.

ColorEnvelope

ColorEnvelope is a data transfer object that includes updated color factors. If you pass the onColorChanged lambda function to the ImageColorPicker or HsvColorPicker, the lambda receives ColorEnvelope. ColorEnvelope includes the following properties:

onColorChanged = { colorEnvelope: ColorEnvelope ->
    val color: Color = colorEnvelope.color // ARGB color value.
    val hexCode: String = colorEnvelope.hexCode // Color hex code, which represents color value.
    val fromUser: Boolean = colorEnvelope.fromUser // Represents this event is triggered by user or not.
}

ColorPickerController

ColorPickerController interacts with color pickers and it allows you to control the all subcomponents.

Custom Wheel

You can customize the wheel with the following functions:

.setWheelRadius(40.dp) // set the radius size of the wheel.
.setWheelColor(Color.Blue) // set the color of the wheel.
.setWheelAlpha(0.5f) // set the transparency of the wheel.
.setWheelImageBitmap(imageBitmap) // set the wheel image with your custom ImageBitmap.

Select Points

You can select specific points with the functions below:

.selectByCoordinate(x = 100f, y = 100f, fromUser = false) // select x = 100, y = 100.
.selectCenter(fromUser = false) // select center of the palette.

Debounce

You can set the debounce duration, which decides to invoke the color listener from the last tapping. Debounce can be useful to reduce overhead. For example, communicating with IoT devices or relevant works that require heavy operations.

controller.debounceDuration = 200L

Enable and Disable

You can enable or disable your color picker with the below function:

controller.enabled = false

AlphaSlider

AlphaSlider allows you to adjust the alpha value of the selected color from color pickers. AlphaSlider needs to be tied to the ColorPickerController, and the value changes will be assembled with the selected color factors. You can implement AlphaSlider as the following example:

AlphaSlider(
    modifier = Modifier
        .fillMaxWidth()
        .padding(10.dp)
        .height(35.dp),
    controller = controller,
)

You can customize the border of the sider with the following parameters:

AlphaSlider(
    borderRadius = 6.dp,
    borderSize = 5.dp,
    borderColor = Color.LightGray,
    ..
)

You can customize the wheel of the sider with the following parameters:

AlphaSlider(
    wheelRadius = 30.dp,
    wheelColor = Color.White,
    wheelPaint = Paint().apply { color = wheelColor },
    wheelImageBitmap = ImageBitmap.imageResource(R.drawable.wheel),
    ..
)

Also, you can customize tiles of the background with the following parameters:

AlphaSlider(
    tileOddColor = Color.White,
    tileEvenColor = Color.LightGray,
    tileSize = 30.dp,
    ..
)

BrightnessSlider

BrightnessSlider allows you to adjust the brightness value of the selected color from color pickers. BrightnessSlider needs to be tied to the ColorPickerController, and the value changes will be assembled with the selected color factors. You can implement BrightnessSlider as the following example:

BrightnessSlider(
    modifier = Modifier
        .fillMaxWidth()
        .padding(10.dp)
        .height(35.dp),
    controller = controller,
)

You can customize the wheel of the sider with the following parameters:

BrightnessSlider(
    wheelRadius = 30.dp,
    wheelColor = Color.White,
    wheelPaint = Paint().apply { color = wheelColor },
    wheelImageBitmap = ImageBitmap.imageResource(R.drawable.wheel),
    ..
)

AlphaTile

AlphaTile allows you to display ARGB colors including transparency with tiles.

AlphaTile(
    modifier = Modifier
        .size(80.dp)
        .clip(RoundedCornerShape(6.dp)),
    controller = controller
)

Also, you can customize tiles of the background with the following parameters:

AlphaTile(
    tileOddColor = Color.White,
    tileEvenColor = Color.LightGray,
    tileSize = 30.dp,
    ..
)

Find this repository useful? โค๏ธ

Support it by joining stargazers for this repository. โญ
Also, follow me on GitHub for my next creations! ๐Ÿคฉ

License

Designed and developed by 2022 skydoves (Jaewoong Eum)

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.

colorpicker-compose's People

Contributors

coderforlife avatar daannnnn avatar darktiny avatar kitakkun avatar lhoyong avatar lucasginard avatar moertel avatar ruigoncalo avatar sderr avatar skydoves avatar tberghuis avatar tejpbit avatar tomveich avatar turaib avatar yangsooplus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

colorpicker-compose's Issues

Brightness slider not showing black (v1.0.5)

Please complete the following information:

  • Library Version [e.g. v1.0.5]
  • Affected Device(s) [e.g. Pixel 6 Android 13]

Describe the Bug:

Brightness slider is white on left side

Expected Behavior:

The brightness slider should be black on the left side, instead it's white.

Here's a screenshot displaying the issue

Screenshot_20231019-143031

Color code input field

Great library, very useful and easy to use!
I want to recommend adding a field where the user can enter a color code whether the hex or argb value, the field would be connected to the controller of course, and the color then be applied to both the hsv wheel and the alpha tile. if this can already be achieved by the current version, I would really appreciate an example of how to do it. Thank you.

Wrong border size is applied

  • Library Version v1.0.1
  • Affected Device(s) - all

Bug description:

When setting the borderSize for the BrightnessSlider the value is defined in DP. However the library does not converts it into pixels, but just takes the DP value:

strokeWidth = borderSize.value

This causes that 5.dp border is applied as 5.px.

Same issue is with the borderSize when it is applied with .drawRoundRect

Expected Behavior:

The DP should be properly calculated to pixels (according to the current density), so the correct size is applied

Allow to set HsvColorPicker color and BrightnessSlider value manually

I use this code to set the color, but I'm not able to set the brightness

`val hsv = FloatArray(3)
val color = Color(initialColor)
RGBToHSV(
(color.red * 255).toInt(),
(color.green * 255).toInt(),
(color.blue * 255).toInt(),
hsv)
val pickerWidth = 500f
val radius = pickerWidth / 2f
val colorRadius: Float = hsv[1] * radius
val angle: Double = ((1 - (hsv[0] / 360f)) * (2 * Math.PI))
val midX: Float = pickerWidth / 2f //midpoint of the circle
val midY: Float = pickerWidth / 2f
val xOffset: Float =
(kotlin.math.cos(angle) * colorRadius).toFloat() //offset from the midpoint of the circle
val yOffset: Double = sin(angle) * colorRadius
val x = midX + xOffset
val y = midY + yOffset

                        controller.selectByCoordinate(x, y.toFloat(), fromUser = false)`

Regarding the brightness the setBrightness function should be public

setBrighness function of ColorController is internal

Please complete the following information:

  • Library Version: 1.0.5
  • Affected Device: Every device; Samsung Galaxy S21 5G (in my case)

Describe the Bug:

The function set set the brightness of the slider is set to internal.

Expected Behavior:

This function should be public (so you can set the brightness by your own).
At least there should be a possibility to reset the brightness, like the selectCenter funtion of the color wheel.

Could not resolve all dependencies for configuration

Please complete the following information:

  • Library Version [v1.0.5]
  • Affected Device(s) [Pixel 7 Pro]

Describe the Bug:
Added the dependencia in the build gradle and it throws this

FAILURE: Build failed with an exception.

  • What went wrong:
    Could not resolve all dependencies for configuration ':app:debugRuntimeClasspath'.
    Problems reading data from Binary store in C:\Users\phgfu.gradle.tmp\gradle9238719398653078878.bin offset 68796 exists? true
    Corrupt serialized resolution result. Cannot find selected module (602) for releaseRuntimeElements-published -> androidx.compose.material3:material3-window-size-class

  • Try:

Run with --info or --debug option to get more log output.
Run with --scan to get full insights.

  • Exception is:
    com.intellij.openapi.externalSystem.model.ExternalSystemException: Could not resolve all dependencies for configuration ':app:debugRuntimeClasspath'.
    Problems reading data from Binary store in C:\Users\phgfu.gradle.tmp\gradle9238719398653078878.bin offset 68796 exists? true
    Corrupt serialized resolution result. Cannot find selected module (602) for releaseRuntimeElements-published -> androidx.compose.material3:material3-window-size-class
    at org.jetbrains.plugins.gradle.model.ProjectImportAction.addBuildModels(ProjectImportAction.java:412)
    at org.jetbrains.plugins.gradle.model.ProjectImportAction.execute(ProjectImportAction.java:138)
    at org.jetbrains.plugins.gradle.model.ProjectImportAction.execute(ProjectImportAction.java:42)
    at org.gradle.tooling.internal.consumer.connection.InternalBuildActionAdapter.execute(InternalBuildActionAdapter.java:64)
    at ...

Add a clear description about the problem.
Jus added the dependencia and clicked Sync now and it throws that

Sorry Im new to android so maybe it can be a stupidity.

Sorry for my english btw. Regards from Spain

Not able to set value of alpha and brightness sliders to 0

  • Library Version v1.0.0

The values of alpha and brightness sliders cannot be set to 0.

As you can see in this screenshot, If I slide the alpha slider to the leftmost side, it's value only gets to #09 instead of #00

This also applies to the brightness slider.

HsvColorPicker selectByColor() can't set color (0,1,1)

  • Library Version [e.g. v1.0.7]
  • Affected Device(s) [Samsung Galaxy s20 with Android 13, Emulator Pixel 7Pro wit Android 14]

Describe the Bug:

Tried using the setByColor() method to set color Color(0.0, 1.0, 1.0, 1.0, sRGB IEC61966-2.1) into the HsvColorPicker, it was not set.

Apparently it calculates the coordinates to be set by the setByCoordinate() method, that color result in a coordinate (x=0.0, y=627.0) which makes extractPixelHsvColor() function in the setByCoordinate() method to return Color.Transparent and failing to set the color.

Expected Behavior:

I expected the color Color(0.0, 1.0, 1.0, 1.0, sRGB IEC61966-2.1) to be set in the HsvColorPicker.

why I get java.lang.IllegalAccessException: Can't set an ImageBitmap before initializing the canvas ?

I'm doing what exactly u said, but still I get this:
java.lang.IllegalAccessException: Can't set an ImageBitmap before initializing the canvas

why is that?

code:

    val controller = rememberColorPickerController()
    val context = LocalContext.current
    val bitmap = imageUri.getBitmap(context).asImageBitmap()
    controller.setPaletteImageBitmap(bitmap)

getBitmap():

fun Uri.getBitmap(context: Context): Bitmap =
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) ImageDecoder.decodeBitmap(
        ImageDecoder.createSource(
            context.contentResolver,
            this
        )
    )
    else MediaStore.Images.Media.getBitmap(context.contentResolver, this)

Set wheel alpha only applies to picker not sliders

Please complete the following information:

  • Library Version: v1.0.1

Describe the Bug:
Set wheel alpha only applies to picker not sliders. The little white dot is still pure white on the others. This probably applies to all of the "wheel" settings. I would expect them to all be consistent.

Debounce does not work with the brightness slider

  • Library Version 1.0.2
  • Affected Device: Samsung Galaxy s22 with Android 11.0

Describe the Bug:

Add a clear description about the problem.
If I set the debounce time on the controller, it has no effect on the brightness slider.

Expected Behavior:
Like the HSV colorpicker, the onColorChanged callback should only be called with a regularity corresponding to the debounce time.

HsvColorPicker resets ViewModel UiStatus

Please complete the following information:

  • Library Version [e.g. v1.0.7]
  • Affected Device(s) [virtual Pixel 7 API 33]

Describe the Bug:

When using the HsvColorPicker to update the attribute of a ViewModel it resets the other attributes of it. Here is an example code:
The ViewModel class looks something like this

class EditTagViewModel(
    private val appRepository: AppRepository,
    savedStateHandle: SavedStateHandle
): ViewModel() {
    private val boxId: Long = checkNotNull(savedStateHandle["boxId"])
    var tagUiState by mutableStateOf(TagState())

    fun updateUiState(tagDetails: TagDetails) {
        tagUiState = TagState(
            tagDetails = tagDetails
        )
    }
}

where TagState has the property TagDetails which holds the text and color.

The composable looks like this

OutlinedTextField(
    value = tagUiState.tagDetails.text,
    label = { Text(text = "Tag Name") },
    onValueChange = {
        editTagViewModel.updateUiState(
            tagUiState.tagDetails.copy(text = it)
        )
    }
)

HsvColorPicker(
    modifier = Modifier
        .fillMaxWidth()
        .height(200.dp),
    controller = controller,
    onColorChanged = { colorEnvelope: ColorEnvelope ->
        editTagViewModel.updateUiState(
            tagUiState.tagDetails.copy(color = colorEnvelope.hexCode)
    }
)

First setting the color and then the text works as expected.

Expected Behavior:

A color change on the HsvColorPicker only changes the color attribute, and does not reset the text. I am not an expert but this might be a problem of scope.

Lots of log with Demo Picker : Called getWidth() on a recycle()'d bitmap! This is undefined behavior!

Hi there

Please complete the following information:

  • Library Version : 1.0.7
  • Affected Device(s) : Pixel 6 @ Android14

With a simple HSV Picker without any bitmap :

val controller = rememberColorPickerController()
HsvColorPicker(
                initialColor= value,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(450.dp)
                    .padding(10.dp),
                controller = controller,
                onColorChanged = { colorEnvelope: ColorEnvelope ->
                   
                }
            )

I get a ton of logs for each touch/drag in the picker zone :

Called getWidth() on a recycle()'d bitmap! This is undefined behavior!
Called getHeight() on a recycle()'d bitmap! This is undefined behavior!
Called getWidth() on a recycle()'d bitmap! This is undefined behavior!
Called getHeight() on a recycle()'d bitmap! This is undefined behavior!
Called getWidth() on a recycle()'d bitmap! This is undefined behavior!
Called getHeight() on a recycle()'d bitmap! This is undefined behavior!
Called getWidth() on a recycle()'d bitmap! This is undefined behavior!
Called getHeight() on a recycle()'d bitmap! This is undefined behavior!
Called getWidth() on a recycle()'d bitmap! This is undefined behavior!
Called getHeight() on a recycle()'d bitmap! This is undefined behavior!

Except this logcat pollution, everything works like a charm :)

Border for BrightnessSlider not showing

Please complete the following information:

  • Library Version [v1.0.4]
  • Affected Device(s) [Pixel 7 with Android 13]

Describe the Bug:

There is no border rendering for BrightnessSlider.

Expected Behavior:

The BrightnessSlider should display the specified border.

Code example:

  val controller = rememberColorPickerController()
  var hexCode by remember { mutableStateOf("") }
  var color: Color by remember { mutableStateOf(Color.Black) }

  Column(
      modifier = Modifier
          .fillMaxWidth()
          .padding(8.dp),
      horizontalAlignment = Alignment.CenterHorizontally
  ) {
      HsvColorPicker(
          modifier = Modifier
              .fillMaxWidth()
              .height(250.dp)
              .padding(10.dp),
          controller = controller,
          onColorChanged = { colorEnvelope: ColorEnvelope ->
              color = colorEnvelope.color
              hexCode = colorEnvelope.hexCode
          }
      )

      Spacer(Modifier.height(20.dp))

      BrightnessSlider(
          modifier = Modifier
              .fillMaxWidth()
              .padding(10.dp)
              .height(35.dp),
          controller = controller,
          borderSize = 2.dp,
          borderColor = Color.DarkGray
      )

Screenshot:
photo_2023-08-02_21-04-27

Expose canvas for custom drawing of wheel

Is your feature request related to a problem?

I would like to have a custom wheelImageBitmap which shows a contour and the color selected at the same time.

Describe the solution you'd like:

In HsvColorPicker.kt there's this code:

            val wheelBitmap = controller.wheelBitmap
            if (wheelBitmap == null) {
                canvas.drawCircle(
                    Offset(point.x, point.y),
                    controller.wheelRadius.toPx(),
                    controller.wheelPaint
                )
            } else {
                canvas.drawImage(
                    wheelBitmap,
                    Offset(point.x - wheelBitmap.width / 2, point.y - wheelBitmap.height / 2),
                    Paint()
                )
            }

Both of these are just operating on the canvas, what I would like to suggest is to add an optional parameter drawWheel: (Canvas, PointF) -> Unit which gets invoked here instead, with the two above options as possible function overloads or optional parameters.

Describe alternatives you've considered:

As a workaround, I could replace the wheelBitmap with a transparent image and intercept pointer events to always draw our custom image/canvas at the correct position. It doesn't feel as a good solution however.

Control the color picker from outside

Hi, I'm not sure if it's been implemented yet but I couldn't find it in the documentation.
Is it possible to control the color picker from outside of the composable through the color picker controller variable? I would like to set the color for example, but dynamically after the color picker has been initialised (so the initialColor probably won't be suitable for this)

Thank you

Can't drag to select colour with HsvColorPicker

  • Library Version [1.0.2]
  • Affected Device(s) [Oppo Find x3 Pro A13]

Describe the Bug:
Can only click to set colour with the HsvColorPicker unless there are multiple touches on the screen.
Sorry if that does not make much sense, what I mean is that if I have two or more fingers on the screen I can drag the selector as expected but if I Just have one finger on the selector I cannot drag it.

Below is my code to instantiate the colour picker:

@composable
fun ColorWheelPicker(modifier: Modifier = Modifier) {
val controller = rememberColorPickerController()
HsvColorPicker(
modifier = modifier
.height(450.dp)
.padding(16.dp),
controller = controller
)
}

Expected Behavior:

I am not sure if this the intended behaviour but my expectation was that I would be able to drag the selector with one finger

Selection indicators are huge

Please complete the following information:

  • Library Version: 1.0.0
  • Affected Device: emulator WXGA tablet

Describe the Bug:
The white selector circle is about 5x bigger than in the screenshots in the documentation

Expected Behavior:
Selector to look like the screenshots

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.