I want to use this color pikcerdialog https://code.google.com/p/android-color-picker/ but i have no idea what to do. I've added external jars and stuff before but this is different when you download it you get a project. I'm not to new to android but am still relatively new. Is that whole project the library or something. I really don't know where to begin but would really like help. even a link to a tutorial would be nice because i dont know what to search.
package com.example.color;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.preference.PreferenceManager;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class AboutDialog extends AlertDialog {
private ImageView mIconView;
private TextView mAppNameText;
private TextView mAboutText;
private TextView mVersionText;
public AboutDialog(Context context) {
super(context);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.dialog, null);
mAboutText = (TextView) layout.findViewById(android.R.id.text2);
mVersionText = (TextView) layout.findViewById(android.R.id.text1);
mAppNameText = (TextView) layout.findViewById(android.R.id.title);
mIconView = (ImageView) layout.findViewById(android.R.id.icon);
setView(layout);
loadAbout();
setTitle("About");
mIconView.setOnClickListener(new View.OnClickListener() {
int mClickCount = 0;
#Override
public void onClick(View v) {
mClickCount++;
if(mClickCount == 5) {
Toast.makeText(getContext(), "Upgraded to Pro Version!", Toast.LENGTH_SHORT).show();
new Thread(new Runnable() {
#Override
public void run() {
SharedPreferences.Editor edit = PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
edit.putBoolean("is_pro", true);
edit.commit();
}
}).start();
}
}
});
setButton(DialogInterface.BUTTON_POSITIVE, getContext().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
}
private void loadAbout(){
PackageInfo pi = null;
try {
pi = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), 0);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
mAppNameText.setText("ColorPickerView");
mVersionText.setText("Version" + " " + (pi != null ? pi.versionName : "null"));
String s = "<b>Developed By:</b><br>Daniel Nilsson<br>";
mAboutText.setText(Html.fromHtml(s));
}
}
That was the dialog and this is just a really simple activity where i call it from
package com.example.color;
import com.example.color.ColorPickerDialog.OnColorChangedListener;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnColorChangedListener, OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b = (Button) findViewById(R.id.button10);
b.setOnClickListener(this);
}
#Override
public void colorChanged(String key, int color) {
// TODO Auto-generated method stub
// Paint l = Paint.setColor(color);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
ColorPickerDialog color = new ColorPickerDialog(this,this, "picker",Color.BLACK,Color.WHITE);
color.show();
}
}
your welcome to use this modify it to your needs
import android.app.Dialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
public class ColorPickerDialog extends Dialog {
public interface OnColorChangedListener {
void colorChanged(String key, int color);
}
private OnColorChangedListener mListener;
private int mInitialColor, mDefaultColor;
private String mKey;
private class ColorPickerView extends View {
private Paint mPaint;
private float mCurrentHue = 0;
private int mCurrentX = 0, mCurrentY = 0;
private int mCurrentColor, mDefaultColor;
private final int[] mHueBarColors = new int[258];
private int[] mMainColors = new int[65536];
private OnColorChangedListener mListener;
private int width,height;
ColorPickerView(Context c, OnColorChangedListener l, int color,
int defaultColor) {
super(c);
mListener = l;
mDefaultColor = defaultColor;
// Get the current hue from the current color and update the main
// color field
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
mCurrentHue = hsv[0];
updateMainColors();
mCurrentColor = color;
// Initialize the colors of the hue slider bar
int index = 0;
for (float i = 0; i < 256; i += 256 / 42) // Red (#f00) to pink
// (#f0f)
{
mHueBarColors[index] = Color.rgb(255, 0, (int) i);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) // Pink (#f0f) to blue
// (#00f)
{
mHueBarColors[index] = Color.rgb(255 - (int) i, 0, 255);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) // Blue (#00f) to light
// blue (#0ff)
{
mHueBarColors[index] = Color.rgb(0, (int) i, 255);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) // Light blue (#0ff) to
// green (#0f0)
{
mHueBarColors[index] = Color.rgb(0, 255, 255 - (int) i);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) // Green (#0f0) to yellow
// (#ff0)
{
mHueBarColors[index] = Color.rgb((int) i, 255, 0);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) // Yellow (#ff0) to red
// (#f00)
{
mHueBarColors[index] = Color.rgb(255, 255 - (int) i, 0);
index++;
}
// Initializes the Paint that will draw the View
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setTextSize(12);
}
// Get the current selected color from the hue bar
private int getCurrentMainColor() {
int translatedHue = 255 - (int) (mCurrentHue * 255 / 360);
int index = 0;
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb(255, 0, (int) i);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb(255 - (int) i, 0, 255);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb(0, (int) i, 255);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb(0, 255, 255 - (int) i);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb((int) i, 255, 0);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb(255, 255 - (int) i, 0);
index++;
}
return Color.RED;
}
// Update the main field colors depending on the current selected hue
private void updateMainColors() {
int mainColor = getCurrentMainColor();
int index = 0;
int[] topColors = new int[256];
for (int y = 0; y < 256; y++) {
for (int x = 0; x < 256; x++) {
if (y == 0) {
mMainColors[index] = Color.rgb(
255 - (255 - Color.red(mainColor)) * x / 255,
255 - (255 - Color.green(mainColor)) * x / 255,
255 - (255 - Color.blue(mainColor)) * x / 255);
topColors[x] = mMainColors[index];
} else
mMainColors[index] = Color.rgb(
(255 - y) * Color.red(topColors[x]) / 255,
(255 - y) * Color.green(topColors[x]) / 255,
(255 - y) * Color.blue(topColors[x]) / 255);
index++;
}
}
}
#Override
protected void onDraw(Canvas canvas) {
int translatedHue = 255 - (int) (mCurrentHue * 255 / 360);
// Display all the colors of the hue bar with lines
for (int x = 0; x < 256; x++) {
// If this is not the current selected hue, display the actual
// color
if (translatedHue != x) {
mPaint.setColor(mHueBarColors[x]);
mPaint.setStrokeWidth(1);
} else // else display a slightly larger black line
{
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(3);
}
canvas.drawLine(x + 10, 0, x + 10, 40, mPaint);
// canvas.drawLine(0, x+10, 40, x+10, mPaint);
//canvas.drawLine(x + width/27, 0, x + width/27,height/8 , mPaint);
}
// Display the main field colors using LinearGradient
for (int x = 0; x < 256; x++) {
int[] colors = new int[2];
colors[0] = mMainColors[x];
colors[1] = Color.BLACK;
Shader shader = new LinearGradient(0, 50, 0, 306, colors, null,
Shader.TileMode.REPEAT);//0,50,0,306
mPaint.setShader(shader);
canvas.drawLine(x + 10, 50, x + 10, 306, mPaint);
//canvas.drawLine(x + width/27, height/8 + 10, x + width/27, height*(5/6), mPaint);
}
mPaint.setShader(null);
// Display the circle around the currently selected color in the
// main field
if (mCurrentX != 0 && mCurrentY != 0) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLACK);
canvas.drawCircle(mCurrentX, mCurrentY, 10, mPaint);
}
// Draw a 'button' with the currently selected color
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mCurrentColor);
//canvas.drawRect(10, 316, 138, 356, mPaint);
//canvas.drawRect(width/27, height*(5/6), width/2, height, mPaint);
// Set the text color according to the brightness of the color
if (Color.red(mCurrentColor) + Color.green(mCurrentColor)
+ Color.blue(mCurrentColor) < 384)
mPaint.setColor(Color.WHITE);
else
mPaint.setColor(Color.BLACK);
// canvas.drawText(
// "New Color", 74,
//340, mPaint);
// Draw a 'button' with the default color
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mDefaultColor);
//canvas.drawRect(138, 316, 266, 356, mPaint);
//canvas.drawRect(width/2, height*(5/6), width, height, mPaint);
// Set the text color according to the brightness of the color
if (Color.red(mDefaultColor) + Color.green(mDefaultColor)
+ Color.blue(mDefaultColor) < 384)
mPaint.setColor(Color.WHITE);
else
mPaint.setColor(Color.BLACK);
//canvas.drawText(
// "Default Color", 202, 340,
//mPaint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(276,366 );//276,366
width = widthMeasureSpec;
height = heightMeasureSpec;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN)
return true;
float x = event.getX();
float y = event.getY();
// If the touch event is located in the hue bar
if (x > 10 && x < 266 && y > 0 && y < 40) {
// Update the main field colors
mCurrentHue = (255 - x) * 360 / 255;
updateMainColors();
// Update the current selected color
int transX = mCurrentX - 10;
int transY = mCurrentY - 60;
int index = 256 * (transY - 1) + transX;
if (index > 0 && index < mMainColors.length)
mCurrentColor = mMainColors[256 * (transY - 1) + transX];
// Force the redraw of the dialog
invalidate();
}
// If the touch event is located in the main field
if (x > 10 && x < 266 && y > 50 && y < 306) {
mCurrentX = (int) x;
mCurrentY = (int) y;
int transX = mCurrentX - 10;
int transY = mCurrentY - 60;
int index = 256 * (transY - 1) + transX;
if (index > 0 && index < mMainColors.length) {
// Update the current color
mCurrentColor = mMainColors[index];
mListener.colorChanged("", mCurrentColor);
// Force the redraw of the dialog
invalidate();
}
}
// If the touch event is located in the left button, notify the
// listener with the current color
//if (x > 10 && x < 138 && y > 316 && y < 356)
// mListener.colorChanged("", mCurrentColor);
// If the touch event is located in the right button, notify the
// listener with the default color
//if (x > 138 && x < 266 && y > 316 && y < 356)
// mListener.colorChanged("", mDefaultColor);
return true;
}
}
public ColorPickerDialog(Context context, OnColorChangedListener listener,
String key, int initialColor, int defaultColor) {
super(context);
mListener = listener;
mKey = key;
mInitialColor = initialColor;
mDefaultColor = defaultColor;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnColorChangedListener l = new OnColorChangedListener() {
public void colorChanged(String key, int color) {
mListener.colorChanged(mKey, color);
dismiss();
}
};
setContentView(new ColorPickerView(getContext(), l, mInitialColor,
mDefaultColor));
setTitle("Pick Text Color");
}
}
Edit how to use in activity
first make activity
implement OnColorChangedListener
then you get the callback function
#Override
public void colorChanged(String key, int color) {
// TODO Auto-generated method stub
paint.setColor(color);
}
and in your code you can make the dialog with the listener like this
ColorPickerDialog color = new ColorPickerDialog(this,this, "picker",Color.BLACK,Color.WHITE);
color.show();
Related
Basically, I cloned a material design widget library and wanted to use the Seekbar view. Even when using match_parent for the width, there was still some padding on the left and right. To combat this, I cloned the project from GitHub and went to the Slider.java class to try and figure out how to truly make this a full length media SeekBar.
I've included my current code, which basically shows a full length seekbar, but starts it a little to the right from the beginning (and consequently stops a little to the left from the end). Here it is mid-media-playback:
CODE
public class Slider extends CustomView {
private int backgroundColor = Color.parseColor("#614E8D");
private Ball ball;
private Bitmap bitmap;
private int max = 100;
private int min = 0;
private NumberIndicator numberIndicator;
private OnValueChangedListener onValueChangedListener;
private boolean placedBall = false;
private boolean press = false;
private boolean showNumberIndicator = false;
private int value = 0;
public Slider(Context context, AttributeSet attrs) {
super(context, attrs);
setAttributes(attrs);
}
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
public int getMin() {
return min;
}
public void setMin(int min) {
this.min = min;
}
public OnValueChangedListener getOnValueChangedListener() {
return onValueChangedListener;
}
public void setOnValueChangedListener(
OnValueChangedListener onValueChangedListener) {
this.onValueChangedListener = onValueChangedListener;
}
// GETERS & SETTERS
public int getValue() {
return value;
}
public void setValue(final int value) {
if (placedBall == false)
post(new Runnable() {
#Override
public void run() {
setValue(value);
}
});
else {
this.value = value;
float division = (ball.xFin - ball.xIni) / max;
ViewHelper.setX(ball,
value * division + getHeight() / 2 - ball.getWidth() / 2);
ball.changeBackground();
}
}
#Override
public void invalidate() {
ball.invalidate();
super.invalidate();
}
public boolean isShowNumberIndicator() {
return showNumberIndicator;
}
public void setShowNumberIndicator(boolean showNumberIndicator) {
this.showNumberIndicator = showNumberIndicator;
numberIndicator = (showNumberIndicator) ? new NumberIndicator(
getContext()) : null;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
isLastTouch = true;
if (isEnabled()) {
if (event.getAction() == MotionEvent.ACTION_DOWN
|| event.getAction() == MotionEvent.ACTION_MOVE) {
if (numberIndicator != null
&& numberIndicator.isShowing() == false)
numberIndicator.show();
if ((event.getX() <= getWidth() && event.getX() >= 0)) {
press = true;
// calculate value
int newValue = 0;
float division = (ball.xFin - ball.xIni) / (max - min);
if (event.getX() > ball.xFin) {
newValue = max;
} else if (event.getX() < ball.xIni) {
newValue = min;
} else {
newValue = min + (int) ((event.getX() - ball.xIni) / division);
}
if (value != newValue) {
value = newValue;
if (onValueChangedListener != null)
onValueChangedListener.onValueChanged(newValue);
}
// move ball indicator
float x = event.getX();
x = (x < ball.xIni) ? ball.xIni : x;
x = (x > ball.xFin) ? ball.xFin : x;
ViewHelper.setX(ball, x);
ball.changeBackground();
// If slider has number indicator
if (numberIndicator != null) {
// move number indicator
numberIndicator.indicator.x = x;
numberIndicator.indicator.finalY = Utils
.getRelativeTop(this) - getHeight() / 2;
numberIndicator.indicator.finalSize = getHeight() / 2;
numberIndicator.numberIndicator.setText("");
}
} else {
press = false;
isLastTouch = false;
if (numberIndicator != null)
numberIndicator.dismiss();
}
} else if (event.getAction() == MotionEvent.ACTION_UP ||
event.getAction() == MotionEvent.ACTION_CANCEL) {
if (numberIndicator != null)
numberIndicator.dismiss();
isLastTouch = false;
press = false;
}
}
return true;
}
#Override
public void setBackgroundColor(int color) {
backgroundColor = color;
if (isEnabled())
beforeBackground = backgroundColor;
}
/**
* Make a dark color to press effect
*
* #return
*/
protected int makePressColor() {
int r = (this.backgroundColor >> 16) & 0xFF;
int g = (this.backgroundColor >> 8) & 0xFF;
int b = (this.backgroundColor >> 0) & 0xFF;
r = (r - 30 < 0) ? 0 : r - 30;
g = (g - 30 < 0) ? 0 : g - 30;
b = (b - 30 < 0) ? 0 : b - 30;
return Color.argb(70, r, g, b);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!placedBall) {
placeBall();
}
Paint paint = new Paint();
if (value == min) {
// Crop line to transparent effect
// before song loaded, basically. Need to make this similar to value != min
if (bitmap == null) {
bitmap = Bitmap.createBitmap(canvas.getWidth(),
canvas.getHeight(), Bitmap.Config.ARGB_8888);
}
Canvas temp = new Canvas(bitmap);
paint.setColor(Color.parseColor("#54457A")); //purple
paint.setStrokeWidth(Utils.dpToPx(2, getResources()));
// temp.drawLine(getHeight() / 2, getHeight() / 2, getWidth()
// - getHeight() / 2, getHeight() / 2, paint);
temp.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, paint);
Paint transparentPaint = new Paint();
transparentPaint.setColor(getResources().getColor(
android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
temp.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
ViewHelper.getY(ball) + ball.getHeight() / 2,
ball.getWidth() / 2, transparentPaint);
canvas.drawBitmap(bitmap, 0, 0, new Paint());
} else {
/*TRACK*/
paint.setColor(Color.parseColor("#5A5A5C")); //track
paint.setStrokeWidth(Utils.dpToPx(10, getResources()));
canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, paint); //track length
paint.setColor(backgroundColor);
/*END TRACK*/
float division = (ball.xFin - ball.xIni) / (max - min);
int value = this.value - min;
//DO NOT TOUCH -- Progress coloring
canvas.drawLine(getHeight() / 2, getHeight() / 2, value * division
+ getHeight() / 2, getHeight() / 2, paint);
}
if (press && !showNumberIndicator) {
paint.setColor(backgroundColor);
paint.setAntiAlias(true);
canvas.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
getHeight() / 2, getHeight() / 3, paint);
}
invalidate();
}
// Set atributtes of XML to View
protected void setAttributes(AttributeSet attrs) {
setBackgroundResource(R.drawable.background_transparent);
// Set size of view
setMinimumHeight(Utils.dpToPx(48, getResources()));
setMinimumWidth(Utils.dpToPx(80, getResources()));
// Set background Color
// Color by resource
int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML,
"background", -1);
if (bacgroundColor != -1) {
setBackgroundColor(getResources().getColor(bacgroundColor));
} else {
// Color by hexadecimal
int background = attrs.getAttributeIntValue(ANDROIDXML, "background", -1);
if (background != -1)
setBackgroundColor(background);
}
showNumberIndicator = attrs.getAttributeBooleanValue(MATERIALDESIGNXML,
"showNumberIndicator", false);
min = attrs.getAttributeIntValue(MATERIALDESIGNXML, "min", 0);
max = attrs.getAttributeIntValue(MATERIALDESIGNXML, "max", 0);
value = attrs.getAttributeIntValue(MATERIALDESIGNXML, "value", min);
ball = new Ball(getContext());
RelativeLayout.LayoutParams params = new LayoutParams(Utils.dpToPx(20,
getResources()), Utils.dpToPx(20, getResources()));
params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
ball.setLayoutParams(params);
addView(ball);
// Set if slider content number indicator
// TODO
if (showNumberIndicator) {
numberIndicator = new NumberIndicator(getContext());
}
}
private void placeBall() {
ViewHelper.setX(ball, getHeight() / 2 - ball.getWidth() / 2);
ViewHelper.setX(ball, ball.getWidth());
ball.xIni = ViewHelper.getX(ball);
ball.xFin = getWidth() - ball.getWidth();// - getHeight() / 2 - ball.getWidth() / 2;
ball.xCen = getWidth() / 2 - ball.getWidth() / 2;
placedBall = true;
}
// Event when slider change value
public interface OnValueChangedListener {
public void onValueChanged(int value);
}
class Ball extends View {
float xIni, xFin, xCen;
public Ball(Context context) {
super(context);
setBackgroundResource(R.drawable.background_switch_ball_uncheck);
}
public void changeBackground() {
if (value != min) {
setBackgroundResource(R.drawable.background_checkbox);
LayerDrawable layer = (LayerDrawable) getBackground();
GradientDrawable shape = (GradientDrawable) layer
.findDrawableByLayerId(R.id.shape_bacground);
shape.setColor(Color.parseColor("#D5C46A")); //yellow ball
} else {
setBackgroundResource(R.drawable.background_switch_ball_uncheck);
}
}
}
// Slider Number Indicator
class Indicator extends RelativeLayout {
boolean animate = true;
// Final size after animation
float finalSize = 0;
// Final y position after animation
float finalY = 0;
boolean numberIndicatorResize = false;
// Size of number indicator
float size = 0;
// Position of number indicator
float x = 0;
float y = 0;
public Indicator(Context context) {
super(context);
setBackgroundColor(getResources().getColor(
android.R.color.transparent));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (numberIndicatorResize == false) {
LayoutParams params = (LayoutParams) numberIndicator.numberIndicator
.getLayoutParams();
params.height = (int) finalSize * 2;
params.width = (int) finalSize * 2;
numberIndicator.numberIndicator.setLayoutParams(params);
}
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(backgroundColor);
if (animate) {
if (y == 0)
y = finalY + finalSize * 2;
y -= Utils.dpToPx(6, getResources());
size += Utils.dpToPx(2, getResources());
}
canvas.drawCircle(
ViewHelper.getX(ball)
+ Utils.getRelativeLeft((View) ball.getParent())
+ ball.getWidth() / 2, y, size, paint);
if (animate && size >= finalSize)
animate = false;
if (animate == false) {
ViewHelper
.setX(numberIndicator.numberIndicator,
(ViewHelper.getX(ball)
+ Utils.getRelativeLeft((View) ball
.getParent()) + ball.getWidth() / 2)
- size);
ViewHelper.setY(numberIndicator.numberIndicator, y - size);
numberIndicator.numberIndicator.setText(value + "");
}
invalidate();
}
}
class NumberIndicator extends Dialog {
Indicator indicator;
TextView numberIndicator;
public NumberIndicator(Context context) {
super(context, android.R.style.Theme_Translucent);
}
#Override
public void dismiss() {
super.dismiss();
indicator.y = 0;
indicator.size = 0;
indicator.animate = true;
}
#Override
public void onBackPressed() {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.number_indicator_spinner);
setCanceledOnTouchOutside(false);
RelativeLayout content = (RelativeLayout) this
.findViewById(R.id.number_indicator_spinner_content);
indicator = new Indicator(this.getContext());
content.addView(indicator);
numberIndicator = new TextView(getContext());
numberIndicator.setTextColor(Color.WHITE);
numberIndicator.setGravity(Gravity.CENTER);
content.addView(numberIndicator);
indicator.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT));
}
}
}
Any help on how to get the circle to start at the very left and end at the very right would be greatly appreciated.
Playing around some more, I found that the original developer of this Slider.java class used a lot of getHeight() / 2 which caused some padding that I didn't want. I've included the edited class. Credit for original class to navasmdc, the creator of Material Design Library.. Feel free to use this class if you need a full sized SeekBar
Slider.java
package com.gc.materialdesign.views;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.gc.materialdesign.R;
import com.gc.materialdesign.utils.Utils;
import com.nineoldandroids.view.ViewHelper;
public class Slider extends CustomView {
private int backgroundColor = Color.parseColor("#614E8D");
private Ball ball;
private Bitmap bitmap;
private int max = 100;
private int min = 0;
private NumberIndicator numberIndicator;
private OnValueChangedListener onValueChangedListener;
private boolean placedBall = false;
private boolean press = false;
private boolean showNumberIndicator = false;
private int value = 0;
public Slider(Context context, AttributeSet attrs) {
super(context, attrs);
setAttributes(attrs);
}
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
public int getMin() {
return min;
}
public void setMin(int min) {
this.min = min;
}
public OnValueChangedListener getOnValueChangedListener() {
return onValueChangedListener;
}
public void setOnValueChangedListener(
OnValueChangedListener onValueChangedListener) {
this.onValueChangedListener = onValueChangedListener;
}
// GETERS & SETTERS
public int getValue() {
return value;
}
public void setValue(final int value) {
if (placedBall == false)
post(new Runnable() {
#Override
public void run() {
setValue(value);
}
});
else {
this.value = value;
float division = (ball.xFin - ball.xIni) / max;
ViewHelper.setX(ball,
value* division);//value * division - ball.getWidth() / 2);
ball.changeBackground();
}
}
#Override
public void invalidate() {
ball.invalidate();
super.invalidate();
}
public boolean isShowNumberIndicator() {
return showNumberIndicator;
}
public void setShowNumberIndicator(boolean showNumberIndicator) {
this.showNumberIndicator = showNumberIndicator;
numberIndicator = (showNumberIndicator) ? new NumberIndicator(
getContext()) : null;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
isLastTouch = true;
if (isEnabled()) {
if (event.getAction() == MotionEvent.ACTION_DOWN
|| event.getAction() == MotionEvent.ACTION_MOVE) {
if (numberIndicator != null
&& numberIndicator.isShowing() == false)
numberIndicator.show();
if ((event.getX() <= getWidth() && event.getX() >= 0)) {
press = true;
// calculate value
int newValue = 0;
float division = (ball.xFin - ball.xIni) / (max - min);
if (event.getX() > ball.xFin) {
newValue = max;
} else if (event.getX() < ball.xIni) {
newValue = min;
} else {
newValue = min + (int) ((event.getX() - ball.xIni) / division);
}
if (value != newValue) {
value = newValue;
if (onValueChangedListener != null)
onValueChangedListener.onValueChanged(newValue);
}
// move ball indicator
float x = event.getX();
x = (x < ball.xIni) ? ball.xIni : x;
x = (x > ball.xFin) ? ball.xFin : x;
ViewHelper.setX(ball, x);
ball.changeBackground();
// If slider has number indicator
if (numberIndicator != null) {
// move number indicator
numberIndicator.indicator.x = x;
numberIndicator.indicator.finalY = Utils
.getRelativeTop(this) - getHeight() / 2;
numberIndicator.indicator.finalSize = getHeight() / 2;
numberIndicator.numberIndicator.setText("");
}
} else {
press = false;
isLastTouch = false;
if (numberIndicator != null)
numberIndicator.dismiss();
}
} else if (event.getAction() == MotionEvent.ACTION_UP ||
event.getAction() == MotionEvent.ACTION_CANCEL) {
if (numberIndicator != null)
numberIndicator.dismiss();
isLastTouch = false;
press = false;
}
}
return true;
}
#Override
public void setBackgroundColor(int color) {
backgroundColor = color;
if (isEnabled())
beforeBackground = backgroundColor;
}
/**
* Make a dark color to press effect
*
* #return
*/
protected int makePressColor() {
int r = (this.backgroundColor >> 16) & 0xFF;
int g = (this.backgroundColor >> 8) & 0xFF;
int b = (this.backgroundColor >> 0) & 0xFF;
r = (r - 30 < 0) ? 0 : r - 30;
g = (g - 30 < 0) ? 0 : g - 30;
b = (b - 30 < 0) ? 0 : b - 30;
return Color.argb(70, r, g, b);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!placedBall) {
placeBall();
}
Paint paint = new Paint();
if (value == min) {
// Crop line to transparent effect
// before song loaded, basically. Need to make this similar to value != min
if (bitmap == null) {
bitmap = Bitmap.createBitmap(canvas.getWidth(),
canvas.getHeight(), Bitmap.Config.ARGB_8888);
}
Canvas temp = new Canvas(bitmap);
paint.setColor(Color.parseColor("#54457A")); //purple
paint.setStrokeWidth(Utils.dpToPx(2, getResources()));
// temp.drawLine(getHeight() / 2, getHeight() / 2, getWidth()
// - getHeight() / 2, getHeight() / 2, paint);
temp.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, paint);
Paint transparentPaint = new Paint();
transparentPaint.setColor(getResources().getColor(
android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
temp.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
ViewHelper.getY(ball) + ball.getHeight() / 2,
ball.getWidth() / 2, transparentPaint);
canvas.drawBitmap(bitmap, 0, 0, new Paint());
} else {
/*TRACK*/
paint.setColor(Color.parseColor("#5A5A5C")); //track
paint.setStrokeWidth(Utils.dpToPx(10, getResources()));
canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, paint); //track length
paint.setColor(backgroundColor);
/*END TRACK*/
float division = (ball.xFin - ball.xIni) / (max - min);
int value = this.value - min;
//DO NOT TOUCH -- Progress coloring
canvas.drawLine(0, getHeight() / 2, value * division
+ball.getWidth(), getHeight() / 2, paint);
}
if (press && !showNumberIndicator) {
paint.setColor(backgroundColor);
paint.setAntiAlias(true);
canvas.drawCircle(ViewHelper.getX(ball) + ball.getWidth() / 2,
getHeight() / 2, getHeight() / 3, paint);
}
invalidate();
}
// Set atributtes of XML to View
protected void setAttributes(AttributeSet attrs) {
setBackgroundResource(R.drawable.background_transparent);
// Set size of view
setMinimumHeight(Utils.dpToPx(48, getResources()));
setMinimumWidth(Utils.dpToPx(80, getResources()));
// Set background Color
// Color by resource
int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML,
"background", -1);
if (bacgroundColor != -1) {
setBackgroundColor(getResources().getColor(bacgroundColor));
} else {
// Color by hexadecimal
int background = attrs.getAttributeIntValue(ANDROIDXML, "background", -1);
if (background != -1)
setBackgroundColor(background);
}
showNumberIndicator = attrs.getAttributeBooleanValue(MATERIALDESIGNXML,
"showNumberIndicator", false);
min = attrs.getAttributeIntValue(MATERIALDESIGNXML, "min", 0);
max = attrs.getAttributeIntValue(MATERIALDESIGNXML, "max", 0);
value = attrs.getAttributeIntValue(MATERIALDESIGNXML, "value", min);
ball = new Ball(getContext());
RelativeLayout.LayoutParams params = new LayoutParams(Utils.dpToPx(20,
getResources()), Utils.dpToPx(20, getResources()));
params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
ball.setLayoutParams(params);
addView(ball);
// Set if slider content number indicator
// TODO
if (showNumberIndicator) {
numberIndicator = new NumberIndicator(getContext());
}
}
private void placeBall() {
// ViewHelper.setX(ball, getHeight() / 2 - ball.getWidth() / 2);
// ViewHelper.setX(ball, 0);
ViewHelper.setX(ball, ball.getWidth());
ball.xIni = 0;//ViewHelper.getX(ball);
ball.xFin = getWidth() - ball.getWidth();// - getHeight() / 2 - ball.getWidth() / 2;
ball.xCen = getWidth() / 2 - ball.getWidth() / 2;
placedBall = true;
}
// Event when slider change value
public interface OnValueChangedListener {
public void onValueChanged(int value);
}
class Ball extends View {
float xIni, xFin, xCen;
public Ball(Context context) {
super(context);
setBackgroundResource(R.drawable.background_switch_ball_uncheck);
}
public void changeBackground() {
if (value != min) {
setBackgroundResource(R.drawable.background_checkbox);
LayerDrawable layer = (LayerDrawable) getBackground();
GradientDrawable shape = (GradientDrawable) layer
.findDrawableByLayerId(R.id.shape_bacground);
shape.setColor(Color.parseColor("#D5C46A")); //yellow ball
} else {
setBackgroundResource(R.drawable.background_switch_ball_uncheck);
}
}
}
// Slider Number Indicator
class Indicator extends RelativeLayout {
boolean animate = true;
// Final size after animation
float finalSize = 0;
// Final y position after animation
float finalY = 0;
boolean numberIndicatorResize = false;
// Size of number indicator
float size = 0;
// Position of number indicator
float x = 0;
float y = 0;
public Indicator(Context context) {
super(context);
setBackgroundColor(getResources().getColor(
android.R.color.transparent));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (numberIndicatorResize == false) {
LayoutParams params = (LayoutParams) numberIndicator.numberIndicator
.getLayoutParams();
params.height = (int) finalSize * 2;
params.width = (int) finalSize * 2;
numberIndicator.numberIndicator.setLayoutParams(params);
}
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(backgroundColor);
if (animate) {
if (y == 0)
y = finalY + finalSize * 2;
y -= Utils.dpToPx(6, getResources());
size += Utils.dpToPx(2, getResources());
}
canvas.drawCircle(
ViewHelper.getX(ball)
+ Utils.getRelativeLeft((View) ball.getParent())
+ ball.getWidth() / 2, y, size, paint);
if (animate && size >= finalSize)
animate = false;
if (animate == false) {
ViewHelper
.setX(numberIndicator.numberIndicator,
(ViewHelper.getX(ball)
+ Utils.getRelativeLeft((View) ball
.getParent()) + ball.getWidth() / 2)
- size);
ViewHelper.setY(numberIndicator.numberIndicator, y - size);
numberIndicator.numberIndicator.setText(value + "");
}
invalidate();
}
}
class NumberIndicator extends Dialog {
Indicator indicator;
TextView numberIndicator;
public NumberIndicator(Context context) {
super(context, android.R.style.Theme_Translucent);
}
#Override
public void dismiss() {
super.dismiss();
indicator.y = 0;
indicator.size = 0;
indicator.animate = true;
}
#Override
public void onBackPressed() {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.number_indicator_spinner);
setCanceledOnTouchOutside(false);
RelativeLayout content = (RelativeLayout) this
.findViewById(R.id.number_indicator_spinner_content);
indicator = new Indicator(this.getContext());
content.addView(indicator);
numberIndicator = new TextView(getContext());
numberIndicator.setTextColor(Color.WHITE);
numberIndicator.setGravity(Gravity.CENTER);
content.addView(numberIndicator);
indicator.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT));
}
}
}
I want to implement the Ringdroid waveform in my android app.But for some songs,the waveform created after choosing the song is larger than the screen size and for songs the waveform width is smaller than the mobile screen width .
Plz suggest me the change in code of Ringdroid ,so that every time the waveform of song totally covers the width of screen.
This is the link of Ringdroid project
https://github.com/google/ringdroid
After a whole lot of searching and surfing about it. I tried it myself and got the desired output with it
This is the WaveformView class of Ringdroid
package com.ringdroid;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import com.ringdroid.soundfile.SoundFile;
/**
* WaveformView is an Android view that displays a visual representation
* of an audio waveform. It retrieves the frame gains from a CheapSoundFile
* object and recomputes the shape contour at several zoom levels.
*
* This class doesn't handle selection or any of the touch interactions
* directly, so it exposes a listener interface. The class that embeds
* this view should add itself as a listener and make the view scroll
* and respond to other events appropriately.
*
* WaveformView doesn't actually handle selection, but it will just display
* the selected part of the waveform in a different color.
*/
public class WaveformView extends View {
public interface WaveformListener {
public void waveformTouchStart(float x);
public void waveformTouchMove(float x);
public void waveformTouchEnd();
public void waveformFling(float x);
public void waveformDraw();
public void waveformZoomIn();
public void waveformZoomOut();
};
// Colors
private Paint mGridPaint;
private Paint mSelectedLinePaint;
private Paint mUnselectedLinePaint;
private Paint mUnselectedBkgndLinePaint;
private Paint mBorderLinePaint;
private Paint mPlaybackLinePaint;
private Paint mTimecodePaint;
private SoundFile mSoundFile;
private int[] mLenByZoomLevel;
private double[][] mValuesByZoomLevel;
private double[] mZoomFactorByZoomLevel;
private int[] mHeightsAtThisZoomLevel;
private int mZoomLevel;
private int mNumZoomLevels;
private int mSampleRate;
private int mSamplesPerFrame;
private int mOffset;
private int mSelectionStart;
private int mSelectionEnd;
private int mPlaybackPos;
private float mDensity;
private float mInitialScaleSpan;
private WaveformListener mListener;
private GestureDetector mGestureDetector;
private ScaleGestureDetector mScaleGestureDetector;
private boolean mInitialized;
public WaveformView(Context context, AttributeSet attrs) {
super(context, attrs);
// We don't want keys, the markers get these
setFocusable(false);
Resources res = getResources();
mGridPaint = new Paint();
mGridPaint.setAntiAlias(false);
mGridPaint.setColor(res.getColor(R.color.grid_line));
mSelectedLinePaint = new Paint();
mSelectedLinePaint.setAntiAlias(false);
mSelectedLinePaint.setColor(res.getColor(R.color.waveform_selected));
mUnselectedLinePaint = new Paint();
mUnselectedLinePaint.setAntiAlias(false);
mUnselectedLinePaint.setColor(res.getColor(R.color.waveform_unselected));
mUnselectedBkgndLinePaint = new Paint();
mUnselectedBkgndLinePaint.setAntiAlias(false);
mUnselectedBkgndLinePaint.setColor(res.getColor(R.color.waveform_unselected_bkgnd_overlay));
mBorderLinePaint = new Paint();
mBorderLinePaint.setAntiAlias(true);
mBorderLinePaint.setStrokeWidth(1.5f);
mBorderLinePaint.setPathEffect(new DashPathEffect(new float[] { 3.0f, 2.0f }, 0.0f));
mBorderLinePaint.setColor(res.getColor(R.color.selection_border));
mPlaybackLinePaint = new Paint();
mPlaybackLinePaint.setAntiAlias(false);
mPlaybackLinePaint.setColor(res.getColor(R.color.playback_indicator));
mTimecodePaint = new Paint();
mTimecodePaint.setTextSize(12);
mTimecodePaint.setAntiAlias(true);
mTimecodePaint.setColor(res.getColor(R.color.timecode));
mTimecodePaint.setShadowLayer(2, 1, 1, res.getColor(R.color.timecode_shadow));
mGestureDetector = new GestureDetector(
context,
new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(MotionEvent e1, MotionEvent e2, float vx, float vy) {
mListener.waveformFling(vx);
return true;
}
}
);
mScaleGestureDetector = new ScaleGestureDetector(
context,
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
public boolean onScaleBegin(ScaleGestureDetector d) {
Log.v("Ringdroid", "ScaleBegin " + d.getCurrentSpanX());
mInitialScaleSpan = Math.abs(d.getCurrentSpanX());
return true;
}
public boolean onScale(ScaleGestureDetector d) {
float scale = Math.abs(d.getCurrentSpanX());
Log.v("Ringdroid", "Scale " + (scale - mInitialScaleSpan));
if (scale - mInitialScaleSpan > 40) {
mListener.waveformZoomIn();
mInitialScaleSpan = scale;
}
if (scale - mInitialScaleSpan < -40) {
mListener.waveformZoomOut();
mInitialScaleSpan = scale;
}
return true;
}
public void onScaleEnd(ScaleGestureDetector d) {
Log.v("Ringdroid", "ScaleEnd " + d.getCurrentSpanX());
}
}
);
mSoundFile = null;
mLenByZoomLevel = null;
mValuesByZoomLevel = null;
mHeightsAtThisZoomLevel = null;
mOffset = 0;
mPlaybackPos = -1;
mSelectionStart = 0;
mSelectionEnd = 0;
mDensity = 1.0f;
mInitialized = false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mScaleGestureDetector.onTouchEvent(event);
if (mGestureDetector.onTouchEvent(event)) {
return true;
}
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
mListener.waveformTouchStart(event.getX());
break;
case MotionEvent.ACTION_MOVE:
mListener.waveformTouchMove(event.getX());
break;
case MotionEvent.ACTION_UP:
mListener.waveformTouchEnd();
break;
}
return true;
}
public boolean hasSoundFile() {
return mSoundFile != null;
}
public void setSoundFile(SoundFile soundFile) {
mSoundFile = soundFile;
mSampleRate = mSoundFile.getSampleRate();
mSamplesPerFrame = mSoundFile.getSamplesPerFrame();
computeDoublesForAllZoomLevels();
mHeightsAtThisZoomLevel = null;
}
public boolean isInitialized() {
return mInitialized;
}
public int getZoomLevel() {
return mZoomLevel;
}
public void setZoomLevel(int zoomLevel) {
while (mZoomLevel > zoomLevel) {
zoomIn();
}
while (mZoomLevel < zoomLevel) {
zoomOut();
}
}
public boolean canZoomIn() {
return (mZoomLevel > 0);
}
public void zoomIn() {
if (canZoomIn()) {
mZoomLevel--;
mSelectionStart *= 2;
mSelectionEnd *= 2;
mHeightsAtThisZoomLevel = null;
int offsetCenter = mOffset + getMeasuredWidth() / 2;
offsetCenter *= 2;
mOffset = offsetCenter - getMeasuredWidth() / 2;
if (mOffset < 0)
mOffset = 0;
invalidate();
}
}
public boolean canZoomOut() {
return (mZoomLevel < mNumZoomLevels - 1);
}
public void zoomOut() {
if (canZoomOut()) {
mZoomLevel++;
mSelectionStart /= 2;
mSelectionEnd /= 2;
int offsetCenter = mOffset + getMeasuredWidth() / 2;
offsetCenter /= 2;
mOffset = offsetCenter - getMeasuredWidth() / 2;
if (mOffset < 0)
mOffset = 0;
mHeightsAtThisZoomLevel = null;
invalidate();
}
}
public int maxPos() {
return mLenByZoomLevel[mZoomLevel];
}
public int secondsToFrames(double seconds) {
return (int)(1.0 * seconds * mSampleRate / mSamplesPerFrame + 0.5);
}
public int secondsToPixels(double seconds) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (int)(z * seconds * mSampleRate / mSamplesPerFrame + 0.5);
}
public double pixelsToSeconds(int pixels) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (pixels * (double)mSamplesPerFrame / (mSampleRate * z));
}
public int millisecsToPixels(int msecs) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (int)((msecs * 1.0 * mSampleRate * z) /
(1000.0 * mSamplesPerFrame) + 0.5);
}
public int pixelsToMillisecs(int pixels) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (int)(pixels * (1000.0 * mSamplesPerFrame) /
(mSampleRate * z) + 0.5);
}
public void setParameters(int start, int end, int offset) {
mSelectionStart = start;
mSelectionEnd = end;
mOffset = offset;
}
public int getStart() {
return mSelectionStart;
}
public int getEnd() {
return mSelectionEnd;
}
public int getOffset() {
return mOffset;
}
public void setPlayback(int pos) {
mPlaybackPos = pos;
}
public void setListener(WaveformListener listener) {
mListener = listener;
}
public void recomputeHeights(float density) {
mHeightsAtThisZoomLevel = null;
mDensity = density;
mTimecodePaint.setTextSize((int)(12 * density));
invalidate();
}
protected void drawWaveformLine(Canvas canvas,
int x, int y0, int y1,
Paint paint) {
canvas.drawLine(x, y0, x, y1, paint);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mSoundFile == null)
return;
if (mHeightsAtThisZoomLevel == null)
computeIntsForThisZoomLevel();
// Draw waveform
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int start = mOffset;
int width = mHeightsAtThisZoomLevel.length - start;
int ctr = measuredHeight / 2;
if (width > measuredWidth)
width = measuredWidth;
// Draw grid
double onePixelInSecs = pixelsToSeconds(1);
boolean onlyEveryFiveSecs = (onePixelInSecs > 1.0 / 50.0);
double fractionalSecs = mOffset * onePixelInSecs;
int integerSecs = (int) fractionalSecs;
int i = 0;
while (i < width) {
i++;
fractionalSecs += onePixelInSecs;
int integerSecsNew = (int) fractionalSecs;
if (integerSecsNew != integerSecs) {
integerSecs = integerSecsNew;
if (!onlyEveryFiveSecs || 0 == (integerSecs % 5)) {
canvas.drawLine(i, 0, i, measuredHeight, mGridPaint);
}
}
}
// Draw waveform
for (i = 0; i < width; i++) {
Paint paint;
if (i + start >= mSelectionStart &&
i + start < mSelectionEnd) {
paint = mSelectedLinePaint;
} else {
drawWaveformLine(canvas, i, 0, measuredHeight,
mUnselectedBkgndLinePaint);
paint = mUnselectedLinePaint;
}
drawWaveformLine(
canvas, i,
ctr - mHeightsAtThisZoomLevel[start + i],
ctr + 1 + mHeightsAtThisZoomLevel[start + i],
paint);
if (i + start == mPlaybackPos) {
canvas.drawLine(i, 0, i, measuredHeight, mPlaybackLinePaint);
}
}
// If we can see the right edge of the waveform, draw the
// non-waveform area to the right as unselected
for (i = width; i < measuredWidth; i++) {
drawWaveformLine(canvas, i, 0, measuredHeight,
mUnselectedBkgndLinePaint);
}
// Draw borders
canvas.drawLine(
mSelectionStart - mOffset + 0.5f, 30,
mSelectionStart - mOffset + 0.5f, measuredHeight,
mBorderLinePaint);
canvas.drawLine(
mSelectionEnd - mOffset + 0.5f, 0,
mSelectionEnd - mOffset + 0.5f, measuredHeight - 30,
mBorderLinePaint);
// Draw timecode
double timecodeIntervalSecs = 1.0;
if (timecodeIntervalSecs / onePixelInSecs < 50) {
timecodeIntervalSecs = 5.0;
}
if (timecodeIntervalSecs / onePixelInSecs < 50) {
timecodeIntervalSecs = 15.0;
}
// Draw grid
fractionalSecs = mOffset * onePixelInSecs;
int integerTimecode = (int) (fractionalSecs / timecodeIntervalSecs);
i = 0;
while (i < width) {
i++;
fractionalSecs += onePixelInSecs;
integerSecs = (int) fractionalSecs;
int integerTimecodeNew = (int) (fractionalSecs /
timecodeIntervalSecs);
if (integerTimecodeNew != integerTimecode) {
integerTimecode = integerTimecodeNew;
// Turn, e.g. 67 seconds into "1:07"
String timecodeMinutes = "" + (integerSecs / 60);
String timecodeSeconds = "" + (integerSecs % 60);
if ((integerSecs % 60) < 10) {
timecodeSeconds = "0" + timecodeSeconds;
}
String timecodeStr = timecodeMinutes + ":" + timecodeSeconds;
float offset = (float) (
0.5 * mTimecodePaint.measureText(timecodeStr));
canvas.drawText(timecodeStr,
i - offset,
(int)(12 * mDensity),
mTimecodePaint);
}
}
if (mListener != null) {
mListener.waveformDraw();
}
}
/**
* Called once when a new sound file is added
*/
private void computeDoublesForAllZoomLevels() {
int numFrames = mSoundFile.getNumFrames();
int[] frameGains = mSoundFile.getFrameGains();
double[] smoothedGains = new double[numFrames];
if (numFrames == 1) {
smoothedGains[0] = frameGains[0];
} else if (numFrames == 2) {
smoothedGains[0] = frameGains[0];
smoothedGains[1] = frameGains[1];
} else if (numFrames > 2) {
smoothedGains[0] = (double)(
(frameGains[0] / 2.0) +
(frameGains[1] / 2.0));
for (int i = 1; i < numFrames - 1; i++) {
smoothedGains[i] = (double)(
(frameGains[i - 1] / 3.0) +
(frameGains[i ] / 3.0) +
(frameGains[i + 1] / 3.0));
}
smoothedGains[numFrames - 1] = (double)(
(frameGains[numFrames - 2] / 2.0) +
(frameGains[numFrames - 1] / 2.0));
}
// Make sure the range is no more than 0 - 255
double maxGain = 1.0;
for (int i = 0; i < numFrames; i++) {
if (smoothedGains[i] > maxGain) {
maxGain = smoothedGains[i];
}
}
double scaleFactor = 1.0;
if (maxGain > 255.0) {
scaleFactor = 255 / maxGain;
}
// Build histogram of 256 bins and figure out the new scaled max
maxGain = 0;
int gainHist[] = new int[256];
for (int i = 0; i < numFrames; i++) {
int smoothedGain = (int)(smoothedGains[i] * scaleFactor);
if (smoothedGain < 0)
smoothedGain = 0;
if (smoothedGain > 255)
smoothedGain = 255;
if (smoothedGain > maxGain)
maxGain = smoothedGain;
gainHist[smoothedGain]++;
}
// Re-calibrate the min to be 5%
double minGain = 0;
int sum = 0;
while (minGain < 255 && sum < numFrames / 20) {
sum += gainHist[(int)minGain];
minGain++;
}
// Re-calibrate the max to be 99%
sum = 0;
while (maxGain > 2 && sum < numFrames / 100) {
sum += gainHist[(int)maxGain];
maxGain--;
}
// Compute the heights
double[] heights = new double[numFrames];
double range = maxGain - minGain;
for (int i = 0; i < numFrames; i++) {
double value = (smoothedGains[i] * scaleFactor - minGain) / range;
if (value < 0.0)
value = 0.0;
if (value > 1.0)
value = 1.0;
heights[i] = value * value;
}
mNumZoomLevels = 5;
mLenByZoomLevel = new int[5];
mZoomFactorByZoomLevel = new double[5];
mValuesByZoomLevel = new double[5][];
// Level 0 is doubled, with interpolated values
mLenByZoomLevel[0] = numFrames * 2;
mZoomFactorByZoomLevel[0] = 2.0;
mValuesByZoomLevel[0] = new double[mLenByZoomLevel[0]];
if (numFrames > 0) {
mValuesByZoomLevel[0][0] = 0.5 * heights[0];
mValuesByZoomLevel[0][1] = heights[0];
}
for (int i = 1; i < numFrames; i++) {
mValuesByZoomLevel[0][2 * i] = 0.5 * (heights[i - 1] + heights[i]);
mValuesByZoomLevel[0][2 * i + 1] = heights[i];
}
// Level 1 is normal
mLenByZoomLevel[1] = numFrames;
mValuesByZoomLevel[1] = new double[mLenByZoomLevel[1]];
mZoomFactorByZoomLevel[1] = 1.0;
for (int i = 0; i < mLenByZoomLevel[1]; i++) {
mValuesByZoomLevel[1][i] = heights[i];
}
// 3 more levels are each halved
for (int j = 2; j < 5; j++) {
mLenByZoomLevel[j] = mLenByZoomLevel[j - 1] / 2;
mValuesByZoomLevel[j] = new double[mLenByZoomLevel[j]];
mZoomFactorByZoomLevel[j] = mZoomFactorByZoomLevel[j - 1] / 2.0;
for (int i = 0; i < mLenByZoomLevel[j]; i++) {
mValuesByZoomLevel[j][i] =
0.5 * (mValuesByZoomLevel[j - 1][2 * i] +
mValuesByZoomLevel[j - 1][2 * i + 1]);
}
}
if (numFrames > 5000) {
mZoomLevel = 3;
} else if (numFrames > 1000) {
mZoomLevel = 2;
} else if (numFrames > 300) {
mZoomLevel = 1;
} else {
mZoomLevel = 0;
}
mInitialized = true;
}
/**
* Called the first time we need to draw when the zoom level has changed
* or the screen is resized
*/
private void computeIntsForThisZoomLevel() {
int halfHeight = (getMeasuredHeight() / 2) - 1;
mHeightsAtThisZoomLevel = new int[mLenByZoomLevel[mZoomLevel]];
for (int i = 0; i < mLenByZoomLevel[mZoomLevel]; i++) {
mHeightsAtThisZoomLevel[i] =
(int)(mValuesByZoomLevel[mZoomLevel][i] * halfHeight);
}
}
}
The change is here in this part of code
DisplayMetrics displaymetrics = getContext().getResources().getDisplayMetrics();
int ScreenWidth= displaymetrics.widthPixels;
// Draw waveform
for ( i = 0; i < width; i++) {
Paint paint;
if (i + start >= mSelectionStart &&
i + start < mSelectionEnd) {
paint = mSelectedLinePaint;
} else {
drawWaveformLine(canvas, ((ScreenWidth/width)*i), 0, measuredHeight,
mUnselectedBkgndLinePaint);
paint = mUnselectedLinePaint;
}
drawWaveformLine(
canvas, ((ScreenWidth/width)*i),
ctr - mHeightsAtThisZoomLevel[start + i],
ctr + 1 + mHeightsAtThisZoomLevel[start + i],
paint);
you have to change the x-axis of draw line method according to your screen size
import java.util.LinkedList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceView;
/**
* A view that displays audio data on the screen as a waveform.
*/
public class WaveformView extends SurfaceView {
// The number of buffer frames to keep around (for a nice fade-out
// visualization.
private static final int HISTORY_SIZE = 6;
// To make quieter sounds still show up well on the display, we use
// +/- 8192 as the amplitude that reaches the top/bottom of the view
// instead of +/- 32767. Any samples that have magnitude higher than this
// limit will simply be clipped during drawing.
private static final float MAX_AMPLITUDE_TO_DRAW = 8192.0f;
// The queue that will hold historical audio data.
private LinkedList<short[]> mAudioData;
private Paint mPaint;
public WaveformView(Context context) {
this(context, null, 0);
}
public WaveformView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WaveformView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mAudioData = new LinkedList<short[]>();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(0);
mPaint.setAntiAlias(true);
}
/**
* Updates the waveform view with a new "frame" of samples and renders it.
* The new frame gets added to the front of the rendering queue, pushing the
* previous frames back, causing them to be faded out visually.
*
* #param buffer the most recent buffer of audio samples.
*/
public synchronized void updateAudioData(short[] buffer) {
short[] newBuffer;
// We want to keep a small amount of history in the view to provide a nice
// fading effect. We use a linked list that we treat as a queue for this.
if (mAudioData.size() == HISTORY_SIZE) {
newBuffer = mAudioData.removeFirst();
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
} else {
newBuffer = buffer.clone();
}
mAudioData.addLast(newBuffer);
// Update the display.
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
drawWaveform(canvas);
getHolder().unlockCanvasAndPost(canvas);
}
}
/**
* Repaints the view's surface.
*
* #param canvas the {#link Canvas} object on which to draw.
*/
private void drawWaveform(Canvas canvas) {
// Clear the screen each time because SurfaceView won't do this for us.
canvas.drawColor(Color.BLACK);
float width = getWidth();
float height = getHeight();
float centerY = height / 2;
// We draw the history from oldest to newest so that the older audio
// data is further back and darker than the most recent data.
int colorDelta = 255 / (HISTORY_SIZE + 1);
int brightness = colorDelta;
for (short[] buffer : mAudioData) {
mPaint.setColor(Color.argb(brightness, 128, 255, 192));
float lastX = -1;
float lastY = -1;
// For efficiency, we don't draw all of the samples in the buffer,
// but only the ones that align with pixel boundaries.
for (int x = 0; x < width; x++) {
int index = (int) ((x / width) * buffer.length);
short sample = buffer[index];
float y = (sample / MAX_AMPLITUDE_TO_DRAW) * centerY + centerY;
if (lastX != -1) {
canvas.drawLine(lastX, lastY, x, y, mPaint);
}
lastX = x;
lastY = y;
}
brightness += colorDelta;
}
}
}
I tried to generate histogram of Image using following code,
package com.example.viewfinderee368;
import java.nio.ByteBuffer;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
#SuppressLint("DrawAllocation")
public class HistogramDemo extends Activity {
Bitmap mainImage;
Bitmap histroImage;
ImageView mainImageView;
LinearLayout histroImageView;
private DrawOnTop mDrawOnTop;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.histrogram);
mainImageView = (ImageView) findViewById(R.id.img);
histroImageView = (LinearLayout) findViewById(R.id.histroImg);
mainImage = ((BitmapDrawable) mainImageView.getDrawable()).getBitmap();
histroImage = Bitmap.createBitmap(mainImage);
mDrawOnTop = new DrawOnTop(this);
mDrawOnTop.mImageWidth = mainImage.getWidth();
mDrawOnTop.mImageHeight = mainImage.getHeight();
mDrawOnTop.mBitmap = Bitmap.createBitmap(mDrawOnTop.mImageWidth,
mDrawOnTop.mImageHeight, Bitmap.Config.RGB_565);
mDrawOnTop.mRGBData = new int[mDrawOnTop.mImageWidth * mDrawOnTop.mImageHeight];
int bytes = mainImage.getByteCount();
//or we can calculate bytes this way. Use a different value than 4 if you don't use 32bit images.
//int bytes = b.getWidth()*b.getHeight()*4;
ByteBuffer buffer = ByteBuffer.allocate(bytes); //Create a new buffer
mainImage.copyPixelsToBuffer(buffer); //Move the byte data to the buffer
byte[] array = buffer.array();
mDrawOnTop.mYUVData =array;
System.arraycopy(array, 0, mDrawOnTop.mYUVData, 0, array.length);
// mDrawOnTop.invalidate();
histroImageView.addView(mDrawOnTop);
}
class DrawOnTop extends View {
Bitmap mBitmap;
Paint mPaintBlack;
Paint mPaintYellow;
Paint mPaintRed;
Paint mPaintGreen;
Paint mPaintBlue;
Paint mPaintGray;
byte[] mYUVData;
int[] mRGBData;
int mImageWidth, mImageHeight;
int[] mRedHistogram;
int[] mGreenHistogram;
int[] mBlueHistogram;
double[] mBinSquared;
private DrawOnTop(Context context) {
super(context);
mPaintBlack = new Paint();
mPaintBlack.setStyle(Paint.Style.FILL);
mPaintBlack.setColor(Color.BLACK);
mPaintBlack.setTextSize(25);
mPaintYellow = new Paint();
mPaintYellow.setStyle(Paint.Style.FILL);
mPaintYellow.setColor(Color.YELLOW);
mPaintYellow.setTextSize(25);
mPaintRed = new Paint();
mPaintRed.setStyle(Paint.Style.FILL);
mPaintRed.setColor(Color.RED);
mPaintRed.setTextSize(25);
mPaintGreen = new Paint();
mPaintGreen.setStyle(Paint.Style.FILL);
mPaintGreen.setColor(Color.GREEN);
mPaintGreen.setTextSize(25);
mPaintBlue = new Paint();
mPaintBlue.setStyle(Paint.Style.FILL);
mPaintBlue.setColor(Color.BLUE);
mPaintBlue.setTextSize(25);
mPaintGray = new Paint();
mPaintGray.setStyle(Paint.Style.FILL);
mPaintGray.setColor(Color.GRAY);
mPaintGray.setTextSize(25);
mBitmap = null;
mYUVData = null;
mRGBData = null;
mRedHistogram = new int[256];
mGreenHistogram = new int[256];
mBlueHistogram = new int[256];
mBinSquared = new double[256];
for (int bin = 0; bin < 256; bin++)
{
mBinSquared[bin] = ((double)bin) * bin;
} // bin
}
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap != null)
{
canvas.drawColor(Color.WHITE);
int canvasWidth = 255;
int canvasHeight =255;
int newImageWidth = canvasWidth;
int newImageHeight = canvasHeight;
int marginWidth = (canvasWidth - newImageWidth)/2;
// Convert from YUV to RGB
decodeYUV420SP(mRGBData, mYUVData, mImageWidth, mImageHeight);
// Draw bitmap
mBitmap.setPixels(mRGBData, 0, mImageWidth, 0, 0,
mImageWidth, mImageHeight);
// Draw black borders
canvas.drawRect(0, 0, marginWidth, canvasHeight, mPaintBlack);
canvas.drawRect(canvasWidth - marginWidth, 0,
canvasWidth, canvasHeight, mPaintBlack);
// Calculate histogram
calculateIntensityHistogram(mRGBData, mRedHistogram,
mImageWidth, mImageHeight, 0);
calculateIntensityHistogram(mRGBData, mGreenHistogram,
mImageWidth, mImageHeight, 1);
calculateIntensityHistogram(mRGBData, mBlueHistogram,
mImageWidth, mImageHeight, 2);
// Calculate mean
double imageRedMean = 0, imageGreenMean = 0, imageBlueMean = 0;
double redHistogramSum = 0, greenHistogramSum = 0, blueHistogramSum = 0;
for (int bin = 0; bin < 256; bin++)
{
imageRedMean += mRedHistogram[bin] * bin;
redHistogramSum += mRedHistogram[bin];
imageGreenMean += mGreenHistogram[bin] * bin;
greenHistogramSum += mGreenHistogram[bin];
imageBlueMean += mBlueHistogram[bin] * bin;
blueHistogramSum += mBlueHistogram[bin];
} // bin
imageRedMean /= redHistogramSum;
imageGreenMean /= greenHistogramSum;
imageBlueMean /= blueHistogramSum;
// Draw red intensity histogram
float barMaxHeight = 5000;
float barWidth = ((float)newImageWidth) / 256;
float barMarginHeight = 2;
RectF barRect = new RectF();
barRect.bottom = canvasHeight -50 ;
barRect.left = marginWidth;
barRect.right = barRect.left + barWidth;
for (int bin = 0; bin < 255; bin++)
{
float prob = (float)mRedHistogram[bin] / (float)redHistogramSum;
barRect.top = barRect.bottom -
Math.min(100,prob*barMaxHeight) - barMarginHeight;
canvas.drawRect(barRect, mPaintBlack);
barRect.top += barMarginHeight;
canvas.drawRect(barRect, mPaintGray);
barRect.left += barWidth;
barRect.right += barWidth;
} // bin
// Draw green intensity histogram
barRect.bottom = canvasHeight -50 ;
barRect.left = marginWidth;
barRect.right = barRect.left + barWidth;
for (int bin = 0; bin < 255; bin++)
{
barRect.top = barRect.bottom - Math.min(100, ((float)mGreenHistogram[bin])/((float)greenHistogramSum) * barMaxHeight) - barMarginHeight;
canvas.drawRect(barRect, mPaintBlack);
barRect.top += barMarginHeight;
canvas.drawRect(barRect, mPaintGray);
barRect.left += barWidth;
barRect.right += barWidth;
} // bin
// Draw blue intensity histogram
barRect.bottom = canvasHeight -50 ;
barRect.left = marginWidth;
barRect.right = barRect.left + barWidth;
for (int bin = 0; bin < 255; bin++)
{
barRect.top = barRect.bottom - Math.min(100, ((float)mBlueHistogram[bin])/((float)blueHistogramSum) * barMaxHeight) - barMarginHeight;
canvas.drawRect(barRect, mPaintBlack);
barRect.top += barMarginHeight;
canvas.drawRect(barRect, mPaintGray);
barRect.left += barWidth;
barRect.right += barWidth;
} // bin
} // end if statement
super.onDraw(canvas);
}
private void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) r = 0; else if (r > 262143) r = 262143;
if (g < 0) g = 0; else if (g > 262143) g = 262143;
if (b < 0) b = 0; else if (b > 262143) b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
}
private void calculateIntensityHistogram(int[] rgb, int[] histogram, int width, int height, int component)
{
for (int bin = 0; bin < 256; bin++)
{
histogram[bin] = 0;
} // bin
if (component == 0) // red
{
for (int pix = 0; pix < width*height; pix += 3)
{
int pixVal = (rgb[pix] >> 16) & 0xff;
histogram[ pixVal ]++;
} // pix
}
else if (component == 1) // green
{
for (int pix = 0; pix < width*height; pix += 3)
{
int pixVal = (rgb[pix] >> 8) & 0xff;
histogram[ pixVal ]++;
} // pix
}
else // blue
{
for (int pix = 0; pix < width*height; pix += 3)
{
int pixVal = rgb[pix] & 0xff;
histogram[ pixVal ]++;
} // pix
}
}
}
}
But its not generating reliable histogram, I need to generate same histogram as in Adobe Photoshop. In ios its generating same histogram as in Adobe Photoshop using following code.
-(void)readImage:(UIImage*)image
{
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
// NSLog(#"histogram width:- %d",width);
// NSLog(#"histogram height:- %d",height);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
for (int yy=0;yy<height; yy++)
{
for (int xx=0; xx<width; xx++)
{
// Now your rawData contains the image data in the RGBA8888 pixel format.
int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
for (int ii = 0 ; ii < 1 ; ++ii)
{
CGFloat red = (rawData[byteIndex] * 1.0) ;
CGFloat green = (rawData[byteIndex + 1] * 1.0) ;
CGFloat blue = (rawData[byteIndex + 2] * 1.0) ;
// CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0;
byteIndex += 4;
// TYPE CASTING ABOVE FLOAT VALUES TO THAT THEY CAN BE MATCHED WITH ARRAY'S INDEX.
int redValue = (int)red;
int greenValue = (int)green;
int blueValue = (int)blue;
// THESE COUNTERS COUNT " TOTAL NUMBER OF PIXELS " FOR THAT Red , Green or Blue Value IN ENTIRE IMAGE.
fltR[redValue]++;
fltG[greenValue]++;
fltB[blueValue]++;
}
}
}
[self makeArrays];
// for (int yy=0;yy<height; yy++)
// {
// for (int xx=0; xx<width; xx++)
// {
// int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
// rawData [byteIndex] = nil;
// }
// }
// rawData = 0;
// rawData = nil;
static unsigned updateCounter = 0;
memset(rawData, updateCounter & 0xff, width*height*4);
free(rawData);
rawData = NULL;
for(int i=0;i<=255;i++){
fltR[i]=0;
fltG[i]=0;
fltB[i]=0;
}
colorSpace = nil;
}
-(void)makeArrays
{
float max=0;
int maxR=0;
int maxG=0;
int maxB=0;
// PERFORMING SUMMESION OF ALL RED , GREEN AND BLUE VLAUES GRADUALLY TO TAKE AVERAGE OF THEM
// NSLog(#"makeArray :- ,fltR[i] = %f ,fltG[i] = %f ,fltB[i] = %f",fltR[i],fltG[i],fltB[i])
for (int i=0; i<=255; i++)
{
// NSLog(#"makeArray :- ,fltR[i] = %f ,fltG[i] = %f ,fltB[i] = %f",fltR[i],fltG[i],fltB[i]);
maxR += fltR[i];
maxG += fltG[i];
maxB += fltB[i];
}
// CALCULATING AVERAGE OF ALL red, green and blue values.
maxR = maxR/255;
maxG = maxG/255;
maxB = maxB/255;
// As I AM GENERATING 3 GRAPHS , ITS COMPULSARY TO KEEP THEM ON SCREEN SO TAKING THEIR AVERAGE.
max = (maxR+maxG+maxB)/3;
// DEVIDED BY 8 TO GET GRAPH OF THE SAME SIZE AS ITS IN PREVIEW
max = max*2.5;
arrAllPoints = [[NSMutableArray alloc] init];
for (int i=0; i<=255; i++)
{
ClsDrawPoint *objPoint = [[ClsDrawPoint alloc] init];
objPoint.x = i;
objPoint.y = fltR[i]*scale/max;
[arrAllPoints addObject:objPoint];
}
redGraphView.arrRedPoints = arrAllPoints;
// redGraphView.graphColor = [UIColor redColor];
redGraphView.graphColor = [UIColor whiteColor];
[redGraphView drawGraphForArray:arrAllPoints]; /* redGraphView is an object of ClsDraw (custom class of UIView) and this call drws graph from the points of arrAllPoints */
arrAllPoints = [[NSMutableArray alloc] init];
for (int i=0; i<=255; i++)
{
ClsDrawPoint *objPoint = [[ClsDrawPoint alloc] init];
objPoint.x = i;
objPoint.y = fltG[i]*scale/max;
[arrAllPoints addObject:objPoint];
}
greenGraphView.arrRedPoints = arrAllPoints;
// greenGraphView.graphColor = [UIColor greenColor];
greenGraphView.graphColor = [UIColor whiteColor];
[greenGraphView drawGraphForArray:arrAllPoints]; /* greenGraphView is an object of ClsDraw (custom class of UIView) and this call drws graph from the points of arrAllPoints */
arrAllPoints = [[NSMutableArray alloc] init];
for (int i=0; i<=255; i++)
{
ClsDrawPoint *objPoint = [[ClsDrawPoint alloc] init];
objPoint.x = i;
objPoint.y = fltB[i]*scale/max;
[arrAllPoints addObject:objPoint];
}
blueGraphView.arrRedPoints = arrAllPoints;
// blueGraphView.graphColor = [UIColor blueColor];
blueGraphView.graphColor = [UIColor whiteColor];
[blueGraphView drawGraphForArray:arrAllPoints]; /* blueGraphView is an object of ClsDraw (custom class of UIView) and this call drws graph from the points of arrAllPoints */
// THE COORDINATE SYSTEM OF IOS IS TOTALLY OPPOSITE TO THAT OF THE MAC'S SO ROTATED IT WITH REFERENCE TO X - axis.
blueGraphView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0,0.0, 0.0);
redGraphView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0,0.0, 0.0);
greenGraphView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0,0.0, 0.0);
}
I tried to find Adobe Photoshop android api for it but i didn't find. Is there other api to develop histogram app?
Thanks,
Finally i got the solution & i created colored histogram with following code,
EDIT :
I have put my complete code,
DangiAndroidHistogram.java
import java.io.IOException;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.example.myandroidhistogram.R;
public class DangiAndroidHistogram extends Activity {
Bitmap bi = null;
boolean isColored;
LinearLayout view;
LinearLayout view_color;
boolean flag;
private int SIZE = 256;
// Red, Green, Blue
private int NUMBER_OF_COLOURS = 3;
public final int RED = 0;
public final int GREEN = 1;
public final int BLUE = 2;
private int[][] colourBins;
private volatile boolean loaded = false;
private int maxY;
private static final int LDPI = 0;
private static final int MDPI = 1;
private static final int TVDPI = 2;
private static final int HDPI = 3;
private static final int XHDPI = 4;
float offset = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setContentView(R.layout.activity_main);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
if(metrics.densityDpi==metrics.DENSITY_LOW)
offset = 0.75f;
else if(metrics.densityDpi==metrics.DENSITY_MEDIUM)
offset = 1f;
else if(metrics.densityDpi==metrics.DENSITY_TV)
offset = 1.33f;
else if(metrics.densityDpi==metrics.DENSITY_HIGH)
offset = 1.5f;
else if(metrics.densityDpi==metrics.DENSITY_XHIGH)
offset = 2f;
Log.e("NIRAV",""+offset);
colourBins = new int[NUMBER_OF_COLOURS][];
for (int i = 0; i < NUMBER_OF_COLOURS; i++) {
colourBins[i] = new int[SIZE];
}
loaded = false;
Button upload = (Button) findViewById(R.id.upload);
upload.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (flag) {
view_color.removeAllViews();
view.removeAllViews();
}
Intent it = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI);
startActivityForResult(it, 101);
flag = true;
/*
* LinearLayout view = (LinearLayout) findViewById(R.id.lyt);
* view.addView(new MyHistogram(getApplicationContext()));
*/
}
});
Button histogram = (Button) findViewById(R.id.hst_btn);
histogram.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (bi != null) {
isColored = false;
view = (LinearLayout) findViewById(R.id.lyt);
view.addView(new MyHistogram(getApplicationContext(), bi));
}
}
});
Button histogram_color = (Button) findViewById(R.id.hst_color_btn);
histogram_color.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (bi != null) {
isColored = true;
view_color = (LinearLayout) findViewById(R.id.lyt_color);
view_color.addView(new MyHistogram(getApplicationContext(),
bi));
}
}
});
}
protected void onActivityResult(int requestCode, int resultCode,
Intent imageReturnedIntent) {
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
switch (requestCode) {
case 101:
if (resultCode == RESULT_OK) {
Uri selectedImage = imageReturnedIntent.getData();
String filename = getRealPathFromURI(selectedImage);
bi = BitmapFactory.decodeFile(filename);
/*
ByteArrayOutputStream out = new ByteArrayOutputStream();
bi.compress(Bitmap.CompressFormat.JPEG,10,out);
bi = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));*/
if(bi!=null)
{
try {
new MyAsync().execute();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public String getRealPathFromURI(Uri contentUri) {
Log.e("TEST", "GetRealPath : " + contentUri);
try {
if (contentUri.toString().contains("video")) {
String[] proj = { MediaStore.Video.Media.DATA };
Cursor cursor = managedQuery(contentUri, proj, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else {
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(contentUri, proj, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
class MyAsync extends AsyncTask
{
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
showDialog(0);
}
#Override
protected Object doInBackground(Object... params) {
// TODO Auto-generated method stub
try {
load(bi);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Object result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
ImageView img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(bi);
((Button) findViewById(R.id.hst_btn)).setVisibility(View.VISIBLE);
((Button) findViewById(R.id.hst_color_btn)).setVisibility(View.VISIBLE);
dismissDialog(0);
}
}
public void load(Bitmap bi) throws IOException {
if (bi != null) {
// Reset all the bins
for (int i = 0; i < NUMBER_OF_COLOURS; i++) {
for (int j = 0; j < SIZE; j++) {
colourBins[i][j] = 0;
}
}
for (int x = 0; x < bi.getWidth(); x++) {
for (int y = 0; y < bi.getHeight(); y++) {
int pixel = bi.getPixel(x, y);
colourBins[RED][Color.red(pixel)]++;
colourBins[GREEN][Color.green(pixel)]++;
colourBins[BLUE][Color.blue(pixel)]++;
}
}
maxY = 0;
for (int i = 0; i < NUMBER_OF_COLOURS; i++) {
for (int j = 0; j < SIZE; j++) {
if (maxY < colourBins[i][j]) {
maxY = colourBins[i][j];
}
}
}
loaded = true;
} else {
loaded = false;
}
}
class MyHistogram extends View {
public MyHistogram(Context context, Bitmap bi) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (loaded) {
canvas.drawColor(Color.GRAY);
Log.e("NIRAV", "Height : " + getHeight() + ", Width : "
+ getWidth());
int xInterval = (int) ((double) getWidth() / ((double) SIZE + 1));
for (int i = 0; i < NUMBER_OF_COLOURS; i++) {
Paint wallpaint;
wallpaint = new Paint();
if (isColored) {
if (i == RED) {
wallpaint.setColor(Color.RED);
} else if (i == GREEN) {
wallpaint.setColor(Color.GREEN);
} else if (i == BLUE) {
wallpaint.setColor(Color.BLUE);
}
} else {
wallpaint.setColor(Color.WHITE);
}
wallpaint.setStyle(Style.FILL);
Path wallpath = new Path();
wallpath.reset();
wallpath.moveTo(0, getHeight());
for (int j = 0; j < SIZE - 1; j++) {
int value = (int) (((double) colourBins[i][j] / (double) maxY) * (getHeight()+100));
//if(j==0) {
// wallpath.moveTo(j * xInterval* offset, getHeight() - value);
//}
// else {
wallpath.lineTo(j * xInterval * offset, getHeight() - value);
// }
}
wallpath.lineTo(SIZE * offset, getHeight());
canvas.drawPath(wallpath, wallpaint);
}
}
}
}
#Override
protected Dialog onCreateDialog(int id) {
ProgressDialog dataLoadProgress = new ProgressDialog(this);
dataLoadProgress.setMessage("Loading...");
dataLoadProgress.setIndeterminate(true);
dataLoadProgress.setCancelable(false);
dataLoadProgress.setProgressStyle(android.R.attr.progressBarStyleLarge);
return dataLoadProgress;
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="#android:color/black">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical"
android:background="#android:color/white">
<LinearLayout
android:id="#+id/lyt"
android:layout_width="257dp"
android:layout_height="140dp"
android:orientation="vertical" >
</LinearLayout>
<Button
android:id="#+id/hst_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Histogram"
android:visibility="invisible"/>
<Button
android:id="#+id/hst_color_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Color Histogram"
android:visibility="invisible"/>
<LinearLayout
android:id="#+id/lyt_color"
android:layout_width="257dp"
android:layout_height="140dp"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="#+id/img"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitCenter"
android:src="#drawable/ic_launcher" />
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Select Image"
android:id="#+id/upload"
android:layout_margin="20dp"
android:background="#android:color/white"
android:textColor="#android:color/black"/>
</RelativeLayout>
</LinearLayout>
I hope this example will help others also..!
This is my first Android App and I'm running into some difficulty with drawText(). I have been self-learning Android programming though Mario Zechner's Beginning Android Games. I am adapting the code he uses for the Mr. Nom game in his book to create my own game. This is a color learning game in which the user taps on a grid of colors. I am able to successfully draw the color grid and a space showing the color the user is to "find" using graphics.drawRect(), and a couple of other graphical assets using graphics.drawPixmap(). I am trying to put the name of each color over top of each color filled rectangle. I have thrown in an arbitrary line of text toward the bottom of the code as follows:
p.setTypeface(Typeface.SERIF);
p.setTextSize(100);
p.setColor(Color.WHITE);
p.setStyle(Style.FILL);
canvas.drawPaint(p);
canvas.drawText("RED",120, 120, p);
Reading similar quesitons I believe my issue is that I'm not properly telling it to draw to the same screen as the rest of the graphical elements. I'm sorry if I'm not being clear - again this is my first project. Please let me know what other information you might need in helping me.
Thank you for your time and consideration!
Below is the rest of the java code used:
package com.lilyandrosieshow.colors;
import java.util.List;
import java.util.Random;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.graphics.Paint.Style;
import com.badlogic.androidgames.framework.Game;
import com.badlogic.androidgames.framework.Graphics;
import com.badlogic.androidgames.framework.Input.TouchEvent;
import com.badlogic.androidgames.framework.Screen;
import com.badlogic.androidgames.framework.Sound;
import com.lilyandrosieshow.colors.ColorGrid;
public class GameScreen extends Screen {
Random random = new Random();
World world;
ColorGrid colorGrid = new ColorGrid();
Canvas canvas = new Canvas();
Paint p = new Paint();
static Sound[] colorSoundL = { Assets.lred, Assets.lorange, Assets.lyellow, Assets.lgreen,
Assets.lblue, Assets.lpurple, Assets.lbrown, Assets.lgrey,
Assets.lblack, Assets.lpink, Assets.lcyan, Assets.lwhite };
static Sound[] colorSoundR = { Assets.rred, Assets.rorange, Assets.ryellow, Assets.rgreen,
Assets.rblue, Assets.rpurple, Assets.rbrown, Assets.rgrey,
Assets.rblack, Assets.rpink, Assets.rcyan, Assets.rwhite };
static Sound[] correct1 = { Assets.correct1, Assets.correct2, Assets.correct3, Assets.correct4, Assets.correct5 };
static Sound[] correct2 = { Assets.correcta, Assets.correctb, Assets.correctc, Assets.correctd, Assets.correcte };
static Sound[] wrong1 = {Assets.wrong1, Assets.wrong2, Assets.wrong3, Assets.wrong4, Assets.wrong5 };
static Sound[] wrong2 = {Assets.wronga, Assets.wrongb, Assets.wrongc, Assets.wrongd, Assets.wronge };
static Sound[] ask = {Assets.ask1, Assets.ask2, Assets.ask3, Assets.ask4, Assets.ask5 };
static Sound[] repeat = { Assets.again1, Assets.again2, Assets.again3, Assets.again4, Assets.again5 };
int row = -1;
int column = -1;
public GameScreen(Game game) {
super(game);
this.world = new World();
}
#Override
public void update(float deltaTime) {
List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
// Color Touched
if (event.type == TouchEvent.TOUCH_UP &&
event.x >= 0 && event.x <= 320 && event.y >= 0 && event.y <= 240) {
for (int j = 1; j <= 4; j++){
if (event.x < (j*80)) {
column = j;
break;
}
}
for (int j = 1; j <= 3; j++){
if (event.y < (j*80)) {
row = j;
break;
}
}
updateColorTouched(column, row);
if (world.colorTouched.x == world.colorWanted.x && world.colorTouched.y == world.colorWanted.y) {
correct2[new Random().nextInt(5)].play(1);
if (world.whichHead == World.WhichHead.LILY) colorSoundL[world.colorTouched.id].play(1);
if (world.whichHead == World.WhichHead.ROSIE) colorSoundR[world.colorTouched.id].play(1);
//world.colorTouched.s.play(1);
world.colorWanted = colorGrid.squares.get(random.nextInt(12));
//Assets.ask1.play(1);
//colorSet[colorWanted-1].play(1);
} else {
wrong2[new Random().nextInt(5)].play(1);
//colorSet[colorTouched-1].play(1);
}
}
// A Head Was Touched
if (event.type == TouchEvent.TOUCH_UP && event.y > 240 && event.y <= 480){
if (event.x > 0 && event.x < 160) world.changeVoice(World.WhichHead.LILY);
if (event.x > 161 && event.x < 320) world.changeVoice(World.WhichHead.ROSIE);
}
}
}
#Override
public void present(float deltaTime) { // Draw everything to the screen here
Graphics g = game.getGraphics();
g.drawRect(0, 0, g.getWidth(), g.getHeight(), Color.rgb(75, 75, 75));
g.drawPixmap(Assets.findthis, 5, 245);
g.drawRect(165, 245, 150, 70, Color.rgb(world.colorWanted.r,
world.colorWanted.g,
world.colorWanted.b));
g.drawPixmap(Assets.lilyheadopen, 5, 325, 5, 5, 155, 155);
g.drawPixmap(Assets.rosieheadopen, 165, 325, 5, 5, 155, 155);
// Draws the grid
for (int i = 0; i < 12; i++) {
g.drawRect((
(world.colorGrid.squares.get(i).x-1)*80),
(world.colorGrid.squares.get(i).y-1)*80,
80,
80,
Color.rgb(world.colorGrid.squares.get(i).r, world.colorGrid.squares.get(i).g, world.colorGrid.squares.get(i).b));
// ************* DRAW TEXT NAMES HERE ********************
p.setTypeface(Typeface.SERIF);
p.setTextSize(100);
p.setColor(Color.WHITE);
p.setStyle(Style.FILL);
canvas.drawPaint(p);
canvas.drawText("RED",120, 120, p);
}
}
public void updateColorTouched(int x, int y){
for (int i = 1; i <= 12; i++) {
if (x == world.colorGrid.squares.get(i-1).x && y == world.colorGrid.squares.get(i-1).y){
world.colorTouched = world.colorGrid.squares.get(i-1);
break;
}
}
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
}
}
Rather than drawing to a Canvas object that doesn't get used anywhere, you'll probably want to extend the Graphics interface with a drawText(...) method. This would be analogue to all other draw calls that are defined in Graphics and implemented in AndroidGraphics.
To help you on your way:
Add to Graphics.java:
public void drawText(String text, float x, float y, Paint p);
Add to AndroidGraphics.java:
#Override public void drawText(String text, float x, float y, Paint p) {
paint.set(p);
canvas.drawText(text, x, y, paint);
}
If you need any of the other drawText(...) overloads that are available in Android's Canvas class, you can repeat the same steps as outlined above for those.
try this:
p.setTypeface(Typeface.SERIF);
p.setTextSize(100);
p.setColor(Color.WHITE);
p.setStyle(Style.FILL);
Bitmap bitmap = Bitmap.createBitmap(200,200,Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
//canvas.drawPaint(p);
canvas.drawText("RED",120, 120, p);
g.drawPixmap(new AndroidPixmap(bitmap,PixmapFormat.ARG_8888),839,282);//your actual
//coordinates instead of 839,282 though
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
I am looking for a Color Picker framework which can return color HEX on selection.
I have looked at this wondering if there is some other library I can use.
I know the question is old, but if someone is looking for a great new android color picker that use material design I have forked an great project from github and made a simple-to-use android color picker dialog.
This is the project: Android Color Picker
Android Color Picker dialog
HOW TO USE IT
Adding the library to your project
The aar artifact is available at the jcenter repository. Declare the repository and the
dependency in your build.gradle.
(root)
repositories {
jcenter()
}
(module)
dependencies {
compile 'com.pes.materialcolorpicker:library:1.0.2'
}
Use the library
Create a color picker dialog object
final ColorPicker cp = new ColorPicker(MainActivity.this, defaultColorR, defaultColorG, defaultColorB);
defaultColorR, defaultColorG, defaultColorB are 3 integer ( value 0-255) for the initialization of the color picker with your custom color value. If you don't want to start with a color set them to 0 or use only the first argument
Then show the dialog (when & where you want) and save the selected color
/* Show color picker dialog */
cp.show();
/* On Click listener for the dialog, when the user select the color */
Button okColor = (Button)cp.findViewById(R.id.okColorButton);
okColor.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/* You can get single channel (value 0-255) */
selectedColorR = cp.getRed();
selectedColorG = cp.getGreen();
selectedColorB = cp.getBlue();
/* Or the android RGB Color (see the android Color class reference) */
selectedColorRGB = cp.getColor();
cp.dismiss();
}
});
That's all :)
try this open source projects that might help you
https://github.com/QuadFlask/colorpicker
You can use the following code, it will give you same look as http://code.google.com/p/color-picker-view/
public class ColorPickerDialog extends Dialog {
public interface OnColorChangedListener {
void colorChanged(String key, int color);
}
private OnColorChangedListener mListener;
private int mInitialColor, mDefaultColor;
private String mKey;
private static class ColorPickerView extends View {
private Paint mPaint;
private float mCurrentHue = 0;
private int mCurrentX = 0, mCurrentY = 0;
private int mCurrentColor, mDefaultColor;
private final int[] mHueBarColors = new int[258];
private int[] mMainColors = new int[65536];
private OnColorChangedListener mListener;
ColorPickerView(Context c, OnColorChangedListener l, int color,
int defaultColor) {
super(c);
mListener = l;
mDefaultColor = defaultColor;
// Get the current hue from the current color and update the main
// color field
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
mCurrentHue = hsv[0];
updateMainColors();
mCurrentColor = color;
// Initialize the colors of the hue slider bar
int index = 0;
for (float i = 0; i < 256; i += 256 / 42) // Red (#f00) to pink
// (#f0f)
{
mHueBarColors[index] = Color.rgb(255, 0, (int) i);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) // Pink (#f0f) to blue
// (#00f)
{
mHueBarColors[index] = Color.rgb(255 - (int) i, 0, 255);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) // Blue (#00f) to light
// blue (#0ff)
{
mHueBarColors[index] = Color.rgb(0, (int) i, 255);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) // Light blue (#0ff) to
// green (#0f0)
{
mHueBarColors[index] = Color.rgb(0, 255, 255 - (int) i);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) // Green (#0f0) to yellow
// (#ff0)
{
mHueBarColors[index] = Color.rgb((int) i, 255, 0);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) // Yellow (#ff0) to red
// (#f00)
{
mHueBarColors[index] = Color.rgb(255, 255 - (int) i, 0);
index++;
}
// Initializes the Paint that will draw the View
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setTextSize(12);
}
// Get the current selected color from the hue bar
private int getCurrentMainColor() {
int translatedHue = 255 - (int) (mCurrentHue * 255 / 360);
int index = 0;
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb(255, 0, (int) i);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb(255 - (int) i, 0, 255);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb(0, (int) i, 255);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb(0, 255, 255 - (int) i);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb((int) i, 255, 0);
index++;
}
for (float i = 0; i < 256; i += 256 / 42) {
if (index == translatedHue)
return Color.rgb(255, 255 - (int) i, 0);
index++;
}
return Color.RED;
}
// Update the main field colors depending on the current selected hue
private void updateMainColors() {
int mainColor = getCurrentMainColor();
int index = 0;
int[] topColors = new int[256];
for (int y = 0; y < 256; y++) {
for (int x = 0; x < 256; x++) {
if (y == 0) {
mMainColors[index] = Color.rgb(
255 - (255 - Color.red(mainColor)) * x / 255,
255 - (255 - Color.green(mainColor)) * x / 255,
255 - (255 - Color.blue(mainColor)) * x / 255);
topColors[x] = mMainColors[index];
} else
mMainColors[index] = Color.rgb(
(255 - y) * Color.red(topColors[x]) / 255,
(255 - y) * Color.green(topColors[x]) / 255,
(255 - y) * Color.blue(topColors[x]) / 255);
index++;
}
}
}
#Override
protected void onDraw(Canvas canvas) {
int translatedHue = 255 - (int) (mCurrentHue * 255 / 360);
// Display all the colors of the hue bar with lines
for (int x = 0; x < 256; x++) {
// If this is not the current selected hue, display the actual
// color
if (translatedHue != x) {
mPaint.setColor(mHueBarColors[x]);
mPaint.setStrokeWidth(1);
} else // else display a slightly larger black line
{
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(3);
}
canvas.drawLine(x + 10, 0, x + 10, 40, mPaint);
// canvas.drawLine(0, x+10, 40, x+10, mPaint);
}
// Display the main field colors using LinearGradient
for (int x = 0; x < 256; x++) {
int[] colors = new int[2];
colors[0] = mMainColors[x];
colors[1] = Color.BLACK;
Shader shader = new LinearGradient(0, 50, 0, 306, colors, null,
Shader.TileMode.REPEAT);
mPaint.setShader(shader);
canvas.drawLine(x + 10, 50, x + 10, 306, mPaint);
}
mPaint.setShader(null);
// Display the circle around the currently selected color in the
// main field
if (mCurrentX != 0 && mCurrentY != 0) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLACK);
canvas.drawCircle(mCurrentX, mCurrentY, 10, mPaint);
}
// Draw a 'button' with the currently selected color
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mCurrentColor);
canvas.drawRect(10, 316, 138, 356, mPaint);
// Set the text color according to the brightness of the color
if (Color.red(mCurrentColor) + Color.green(mCurrentColor)
+ Color.blue(mCurrentColor) < 384)
mPaint.setColor(Color.WHITE);
else
mPaint.setColor(Color.BLACK);
canvas.drawText(
getResources()
.getString(R.string.settings_bg_color_confirm), 74,
340, mPaint);
// Draw a 'button' with the default color
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mDefaultColor);
canvas.drawRect(138, 316, 266, 356, mPaint);
// Set the text color according to the brightness of the color
if (Color.red(mDefaultColor) + Color.green(mDefaultColor)
+ Color.blue(mDefaultColor) < 384)
mPaint.setColor(Color.WHITE);
else
mPaint.setColor(Color.BLACK);
canvas.drawText(
getResources().getString(
R.string.settings_default_color_confirm), 202, 340,
mPaint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(276, 366);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN)
return true;
float x = event.getX();
float y = event.getY();
// If the touch event is located in the hue bar
if (x > 10 && x < 266 && y > 0 && y < 40) {
// Update the main field colors
mCurrentHue = (255 - x) * 360 / 255;
updateMainColors();
// Update the current selected color
int transX = mCurrentX - 10;
int transY = mCurrentY - 60;
int index = 256 * (transY - 1) + transX;
if (index > 0 && index < mMainColors.length)
mCurrentColor = mMainColors[256 * (transY - 1) + transX];
// Force the redraw of the dialog
invalidate();
}
// If the touch event is located in the main field
if (x > 10 && x < 266 && y > 50 && y < 306) {
mCurrentX = (int) x;
mCurrentY = (int) y;
int transX = mCurrentX - 10;
int transY = mCurrentY - 60;
int index = 256 * (transY - 1) + transX;
if (index > 0 && index < mMainColors.length) {
// Update the current color
mCurrentColor = mMainColors[index];
// Force the redraw of the dialog
invalidate();
}
}
// If the touch event is located in the left button, notify the
// listener with the current color
if (x > 10 && x < 138 && y > 316 && y < 356)
mListener.colorChanged("", mCurrentColor);
// If the touch event is located in the right button, notify the
// listener with the default color
if (x > 138 && x < 266 && y > 316 && y < 356)
mListener.colorChanged("", mDefaultColor);
return true;
}
}
public ColorPickerDialog(Context context, OnColorChangedListener listener,
String key, int initialColor, int defaultColor) {
super(context);
mListener = listener;
mKey = key;
mInitialColor = initialColor;
mDefaultColor = defaultColor;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnColorChangedListener l = new OnColorChangedListener() {
public void colorChanged(String key, int color) {
mListener.colorChanged(mKey, color);
dismiss();
}
};
setContentView(new ColorPickerView(getContext(), l, mInitialColor,
mDefaultColor));
setTitle(R.string.settings_bg_color_dialog);
}
}
I ended up here looking for a HSV color picker that offered transparency and copy/paste of the hex value. None of the existing answers met those needs, so here's the library I ended up writing:
HSV-Alpha Color Picker for Android (GitHub).
HSV-Alpha Color Picker Demo (Google Play).
I hope it's useful for somebody else.
We have just uploaded AmbilWarna color picker to Maven:
https://github.com/yukuku/ambilwarna
It can be used either as a dialog or as a Preference entry.
If you want a fragment solution, I have made a fork of android-color-picker where DialogFragment is used and is re-created on configuration change. Here's the link: https://github.com/lomza/android-color-picker
Here's another library:
https://github.com/eltos/SimpleDialogFragments
Features color wheel and pallet picker dialogs
Usage for HSV Color picker:
Add the library from maven and in your code just call:
SimpleColorWheelDialog.build()
.color(0xFFCF4747) // optional initial color
.alpha(true)
.show(Activity.this, COLOR_PICKER);
and to get the results let the Activity or fragment implement OnDialogResultListener:
#Override
public boolean onResult(#NonNull String dialogTag, int which, #NonNull Bundle extras) {
if (COLOR_PICKER.equals(dialogTag) && which == BUTTON_POSITIVE){
int color = extras.getInt(SimpleColorWheelDialog.COLOR);
// ...
return true;
}
return false;
}
After some searches in the android references, the newcomer QuadFlask Color Picker seems to be a technically and aesthetically good choice. Also it has Transparency slider and supports HEX coded colors.
Take a look:
QuadFlask Color Picker