I want to draw graph like shown in the attached image.
I already tried by aChartEngine but it's not working successfully.
You could create a SurfaceView, in which you can draw to a Canvas in the onDraw() method. To draw your graph, you can use the Path class, and it's moveTo() and lineTo() methods. To change the appearance of the lines, use the Paint class. Then use the Canvases drawPath() method, which takes a Path, and a Paint object. I think it's a bit easier to start with, than OpenGl.
SurfaceView
Canvas
Path
Paint
Some tutorial
Update:
#Shakti Malik found a pretty good looking library, which looks easy to use: MPAndroidChart
How about trying OpenGL ES ?
you can create a GraphView which will extends GLSurfaceView
example code-
public class GraphView extends GLSurfaceView {
private Renderer renderer;
public GraphView(Context context) {
super(context);
renderer = new GraphRenderer();
setRenderer(renderer);
}
}
And your GraphRender
ublic class GraphRenderer implements Renderer {
public void onDrawFrame(GL10 gl) {
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 1.0f);
gl.glColor4f(1, 0, 0, .5f);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
private void drawGraph(GL10 gl) {
gl.glLineWidth(1.0f);
// put your code here ..
}
public static int loadShader(int type, String shaderCode) {
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
You can try this way.
Example code of Canvas + Paint:
In your XML layout:
<com.y30.histogramdisplay.GraphView
android:id="#+id/histogram_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent" />
In the Activity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GraphView graphView = (GraphView)findViewById(R.id.histogram_view);
int graphArray[] = new int[256];
for(int i = 0; i < graphArray.length; ++i) {
graphArray[i] = i % 50;
}
graphView.setGraphArray(graphArray);
}
And the new View:
public class GraphView extends View {
int m_graphArray[] = null;
int m_maxY = 0;
Paint m_paint;
public GraphView(Context context) {
super(context);
init();
}
public GraphView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public GraphView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
m_paint = new Paint();
m_paint.setColor(Color.BLUE);
m_paint.setStrokeWidth(10);
}
public void setGraphArray(int Xi_graphArray[], int Xi_maxY)
{
m_graphArray = Xi_graphArray;
m_maxY = Xi_maxY;
}
public void setGraphArray(int Xi_graphArray[])
{
int maxY = 0;
for(int i = 0; i < Xi_graphArray.length; ++i)
{
if(Xi_graphArray[i] > maxY)
{
maxY = Xi_graphArray[i];
}
}
setGraphArray(Xi_graphArray, maxY);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(m_graphArray == null)
{
return;
}
int maxX = m_graphArray.length;
float factorX = getWidth() / (float)maxX;
float factorY = getHeight() / (float)m_maxY;
for(int i = 1; i < m_graphArray.length; ++i) {
int x0 = i - 1;
int y0 = m_graphArray[i-1];
int x1 = i;
int y1 = m_graphArray[i];
int sx = (int)(x0 * factorX);
int sy = getHeight() - (int)(y0* factorY);
int ex = (int)(x1*factorX);
int ey = getHeight() - (int)(y1* factorY);
canvas.drawLine(sx, sy, ex, ey, m_paint);
}
}
}
implementation 'com.jjoe64:graphview:4.2.1'
eduGrades = new String[5];
behGrades = new String[5];
eduGrades[0] = getString(R.string.fail);
eduGrades[1] = getString(R.string.pass);
eduGrades[2] = getString(R.string.good);
eduGrades[3] = getString(R.string.very_good);
eduGrades[4] = getString(R.string.excellent);
behGrades[0] = getString(R.string.baad);
behGrades[1] = getString(R.string.accepted);
behGrades[2] = getString(R.string.good);
behGrades[3] = getString(R.string.very_good);
behGrades[4] = getString(R.string.excellent);
DataPoint[] eduDp = new DataPoint[results.size()];
DataPoint[] behDp = new DataPoint[results.size()];
dates = new String[results.size()];
for (int i = 0; i < results.size(); i++) {
dates[i] = results.get(i).getDateOfNote();
eduDp[i] = new DataPoint(i, (double) results.get(i).getEducationEvaluationSign());
behDp[i] = new DataPoint(i, (double) results.get(i).getBehaviorEvaluationSign());
}
LineGraphSeries<DataPoint> eduSeries = new LineGraphSeries<>(eduDp);
educationalGraphView.addSeries(eduSeries);
eduSeries.setDrawBackground(true);
eduSeries.setColor(getResources().getColor(R.color.blue));
eduSeries.setBackgroundColor(getResources().getColor(R.color.blue));
StaticLabelsFormatter staticLabelsFormatter;
staticLabelsFormatter = new StaticLabelsFormatter(educationalGraphView);
staticLabelsFormatter.setVerticalLabels(eduGrades);
staticLabelsFormatter.setHorizontalLabels(dates);
educationalGraphView.getGridLabelRenderer().setHorizontalLabelsColor(getResources().getColor(R.color.colorPrimaryDark));
educationalGraphView.getGridLabelRenderer().setVerticalLabelsColor(getResources().getColor(R.color.colorPrimaryDark));
educationalGraphView.getGridLabelRenderer().setGridColor(getResources().getColor(R.color.white));
educationalGraphView.getGridLabelRenderer().setHorizontalLabelsAngle(145);
educationalGraphView.getGridLabelRenderer().setTextSize(23f);
educationalGraphView.getGridLabelRenderer().setLabelsSpace(20);
educationalGraphView.getGridLabelRenderer().setLabelFormatter(staticLabelsFormatter);
Related
how is possible to set an image or icon in the canvas Circle? i have a custom canvas view that by move the camera on map, resize method will be activate and change the shape of the view and by stop the moving of map it will be like factory setting...happy english :-))))
public class CancvasCircle extends androidx.appcompat.widget.AppCompatImageView {
///main circle resize fields
public static final int MAIN_CIRCLE_PRE_RADIUS = 40;
public static final int MAIN_CIRCLE_POST_RADIUS = 43;
public static final String MAIN_CIRCLE_PRE_STROKE_COLOR = "#69DAE2";
//4CEAE3
public static final String MAIN_CIRCLE_POST_STROKE_COLOR = "#FBCC38";
///// line resize fields
public static final int LINE_HIEGHT_STOP = 45;
public static final int LINE_HIEGHT_START_PRE = 0;
public static final int LINE_HIEGHT_START_POST = 23;
public static final int SHADOW_CIRCLE_PRE_RADIUS = 15;
//circle paint fields
Paint strokeCircle;
Paint fillCircle;
Paint shadowCircle;
Paint line;
Paint dot;
//center
float centerX;
float centerY;
//main circle fields
private int radiusMain = MAIN_CIRCLE_PRE_RADIUS;
private String colorMain = MAIN_CIRCLE_PRE_STROKE_COLOR;
//line fields
private float lineStartY;
private float lineStopY;
//shadow circle fields
private int shadowRadius = SHADOW_CIRCLE_PRE_RADIUS;
public CancvasCircle(Context context) {
super(context);
init();
}
public CancvasCircle(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public CancvasCircle(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init() {
strokeCircle = new Paint();
strokeCircle.setAntiAlias(true);
strokeCircle.setAntiAlias(true);
strokeCircle.setStrokeWidth(10);
strokeCircle.setStyle(Paint.Style.STROKE);
fillCircle = new Paint();
fillCircle.setAntiAlias(true);
fillCircle.setColor(Color.parseColor("#BEC6CC"));
fillCircle.setStyle(Paint.Style.FILL);
shadowCircle = new Paint();
shadowCircle.setAntiAlias(true);
shadowCircle.setColor(Color.parseColor("#1f000000"));
shadowCircle.setStyle(Paint.Style.FILL);
line = new Paint();
line.setAntiAlias(true);
line.setColor(Color.parseColor("#000000"));
line.setStrokeWidth(4);
line.setStyle(Paint.Style.FILL);
dot = new Paint();
dot.setAntiAlias(true);
dot.setColor(Color.parseColor("#000000"));
dot.setStrokeWidth(4);
dot.setStyle(Paint.Style.FILL);
}
public void resizeStrokeCircleParams(Boolean resize) {
if (resize) {
this.radiusMain = MAIN_CIRCLE_POST_RADIUS;
this.colorMain = MAIN_CIRCLE_POST_STROKE_COLOR;
this.lineStartY = centerY - LINE_HIEGHT_START_POST;
this.lineStopY = LINE_HIEGHT_STOP + LINE_HIEGHT_START_POST - 10;
this.shadowRadius = LINE_HIEGHT_START_POST;
} else {
this.radiusMain = MAIN_CIRCLE_PRE_RADIUS;
this.colorMain = MAIN_CIRCLE_PRE_STROKE_COLOR;
this.lineStartY = centerY - LINE_HIEGHT_START_PRE;
this.lineStopY = LINE_HIEGHT_STOP;
this.shadowRadius = SHADOW_CIRCLE_PRE_RADIUS;
}
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
centerX = getWidth() / 2f;
centerY = getHeight() / 2f;
int radius = radiusMain;
float lineStopY = this.lineStopY;
float lineStartY = this.lineStartY;
int shadowRadius = this.shadowRadius;
strokeCircle.setColor(Color.parseColor(colorMain));
canvas.drawCircle(centerX, centerY - lineStopY - radius, radius, strokeCircle);
canvas.drawCircle(centerX, centerY - lineStopY - radius, radius, fillCircle);
canvas.drawCircle(centerX, centerY, shadowRadius, shadowCircle);
canvas.drawLine(centerX, lineStartY, centerX, centerY - lineStopY, line);
canvas.drawPoint(centerX,centerY,dot);
}
}
is it possible to flip two images like coin in it????
See example as custom View.
public class ViewCircle extends View{
final Bitmap bms; //source
final Bitmap bmm; //mask
final Paint paint;
public ViewCircle( Context context ){
super( context );
bms = BitmapFactory.decodeResource( getResources(), R.drawable.pr_0000 );
bmm = Bitmap.createBitmap( bms.getWidth(), bms.getHeight(), Bitmap.Config.ARGB_8888 );
Canvas canvas = new Canvas( bmm );
paint = new Paint( Paint.ANTI_ALIAS_FLAG );
canvas.drawCircle( bmm.getWidth()/2, bmm.getHeight()/2, Math.min(bmm.getWidth()/2,bmm.getHeight()/2), paint );
paint.setXfermode( new PorterDuffXfermode( PorterDuff.Mode.SRC_IN ) );
canvas.drawBitmap( bms, 0, 0, paint );
}
#Override
protected void onDraw( Canvas canvas ){
super.onDraw( canvas );
canvas.drawBitmap( bms, 0,0, null );
canvas.drawBitmap( bmm, bms.getWidth(),0, null );
}
}
i used this method to create a bitmap from XML layout and set it in my codes...
public Bitmap getMarkerBitmapFromView(#DrawableRes int resIdMain, #DrawableRes int resId) {
View customMarkerView = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.custom_marker, null);
customMarkerView.findViewById(R.id.custom_marker_firstlayout);
if(resIdMain != 0){
customMarkerView.setBackgroundResource(resIdMain);
}
ImageView markerImageView = (ImageView) customMarkerView.findViewById(R.id.custom_marker_secondLayout);
if(resId != 0){
markerImageView.setImageResource(resId);
}
customMarkerView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
customMarkerView.layout(0, 0, customMarkerView.getMeasuredWidth(), customMarkerView.getMeasuredHeight());
customMarkerView.buildDrawingCache();
Bitmap returnedBitmap = Bitmap.createBitmap(customMarkerView.getMeasuredWidth(), customMarkerView.getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_IN);
Drawable drawable = customMarkerView.getBackground();
if (drawable != null)
drawable.draw(canvas);
customMarkerView.draw(canvas);
return returnedBitmap;
}
and set it in my canvas view in onDraw() and set it in the middle of my circle:
canvas.drawBitmap(getMarkerBitmapFromView(0,guildMarkerICON),convertDpToPixel(76,context),imageHieght,null);
because of drawing wrong in different devices i used this methods to change pixel and dp:
public static float convertPixelsToDp(float px,Context context){
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
float dp = px / (metrics.densityDpi / 160f);
return dp;
}
public static float convertDpToPixel(float dp,Context context){
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
float px = dp * (metrics.densityDpi/160f);
return px;
}
and XML layout that provide my bit map (that you can use image or any things you want in it) is (custom_marker.xml) :
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/custom_marker_firstlayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/center_marker_background">
<ImageView
android:id="#+id/custom_marker_secondLayout"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
android:contentDescription="#null"
/>
</FrameLayout>
and use this method when you want to change the marker(like moving the map):
map.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
#Override
public void onCameraMoveStarted(int i) {
canvasView.resizeStrokeCircleParams(true,guildMarkerICON);
}
});
map.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
#Override
public void onCameraIdle() {
canvasView.resizeStrokeCircleParams(false,guildMarkerICON);
}
});
and finally here i s my custom canvas class that i used and i passed my custom icon to it by resize method and set it as i want...enjoy it:
public class CancvasCircle extends androidx.appcompat.widget.AppCompatImageView {
///main circle resize fields
public static final int MAIN_CIRCLE_PRE_RADIUS = 24;
public static final int MAIN_CIRCLE_POST_RADIUS = 26;
public static final String MAIN_CIRCLE_PRE_STROKE_COLOR = "#F44336";
public static final String MAIN_CIRCLE_POST_STROKE_COLOR = "#FFCC59";
//FFCC59
//FBCC38
///// line resize fields
public static final int LINE_HIEGHT_STOP = 24;
public static final int LINE_HIEGHT_START_PRE = 0;
public static final int LINE_HIEGHT_START_POST = 11;
public static final int SHADOW_CIRCLE_PRE_RADIUS = 14;
private final Context context;
/// image view fields
//circle paint fields
Paint strokeCircle;
Paint fillCircle;
Paint shadowCircle;
Paint line;
Paint dot;
Paint imagePaint;
//center
float centerX;
float centerY;
//main circle fields
private int radiusMain = MAIN_CIRCLE_PRE_RADIUS;
private String colorMain = MAIN_CIRCLE_PRE_STROKE_COLOR;
//line fieldsاذغ
private float lineStartY;
private float lineStopY;
//shadow circle fields
private int shadowRadius = SHADOW_CIRCLE_PRE_RADIUS;
private Bitmap canvasBitmap;
private int imageTopPadding;
private int guildMarkerICON
;
public CancvasCircle(Context context) {
super(context);
this.context = context;
init();
}
public CancvasCircle(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
public CancvasCircle(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init();
}
public void init() {
strokeCircle = new Paint();
strokeCircle.setAntiAlias(true);
strokeCircle.setAntiAlias(true);
strokeCircle.setStrokeWidth(12);
strokeCircle.setStyle(Paint.Style.STROKE);
fillCircle = new Paint();
fillCircle.setAntiAlias(true);
fillCircle.setColor(Color.parseColor("#af283232"));
fillCircle.setStyle(Paint.Style.FILL);
shadowCircle = new Paint();
shadowCircle.setAntiAlias(true);
shadowCircle.setColor(Color.parseColor("#1f000000"));
shadowCircle.setStyle(Paint.Style.FILL);
line = new Paint();
line.setAntiAlias(true);
line.setColor(Color.parseColor("#000000"));
line.setStrokeWidth(4);
line.setStyle(Paint.Style.FILL);
dot = new Paint();
dot.setAntiAlias(true);
dot.setColor(Color.parseColor("#000000"));
dot.setStrokeWidth(4);
dot.setStyle(Paint.Style.FILL);
}
public void resizeStrokeCircleParams(Boolean resize , int guildMarkerICON) {
this.guildMarkerICON = guildMarkerICON;
if (resize) {
this.radiusMain = (int) convertDpToPixel(MAIN_CIRCLE_POST_RADIUS,context);
this.colorMain = MAIN_CIRCLE_POST_STROKE_COLOR;
this.lineStartY = centerY -convertDpToPixel( LINE_HIEGHT_START_POST,context);
this.lineStopY =convertDpToPixel( LINE_HIEGHT_STOP,context) + convertDpToPixel(LINE_HIEGHT_START_POST,context) -8;
this.shadowRadius = (int) convertDpToPixel(LINE_HIEGHT_START_POST,context);
this.imageTopPadding = (int) convertDpToPixel(19,context);
} else {
this.radiusMain = (int) convertDpToPixel( MAIN_CIRCLE_PRE_RADIUS,context);
this.colorMain = MAIN_CIRCLE_PRE_STROKE_COLOR;
this.lineStartY = centerY - convertDpToPixel(LINE_HIEGHT_START_PRE,context);
this.lineStopY = convertDpToPixel(LINE_HIEGHT_STOP,context);
this.shadowRadius = (int) convertDpToPixel(SHADOW_CIRCLE_PRE_RADIUS,context);
this.imageTopPadding = (int) convertDpToPixel( 28,context);
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
centerX = getWidth() / 2f;
centerY = getHeight() / 2f;
int radius = radiusMain;
float lineStopY = this.lineStopY;
float lineStartY = this.lineStartY;
int shadowRadius = this.shadowRadius;
int imageHieght = this.imageTopPadding;
strokeCircle.setColor(Color.parseColor(colorMain));
// if map is moving (imageHieght == 41)
// if map is not moving (imageHieght == 56)
canvas.drawLine(centerX, lineStartY, centerX, centerY - lineStopY, line);
canvas.drawCircle(centerX, centerY - lineStopY - radius, radius, strokeCircle);
canvas.drawCircle(centerX, centerY - lineStopY - radius, radius, fillCircle);
canvas.drawCircle(centerX, centerY, shadowRadius, shadowCircle);
canvas.drawPoint(centerX,centerY,dot);
canvas.drawBitmap(getMarkerBitmapFromView(0,guildMarkerICON),convertDpToPixel(76,context),imageHieght,null);
invalidate();
}
public static float convertPixelsToDp(float px,Context context){
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
float dp = px / (metrics.densityDpi / 160f);
return dp;
}
public static float convertDpToPixel(float dp,Context context){
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
float px = dp * (metrics.densityDpi/160f);
return px;
}
public Bitmap getMarkerBitmapFromView(#DrawableRes int resIdMain, #DrawableRes int resId) {
View customMarkerView = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.custom_marker, null);
customMarkerView.findViewById(R.id.custom_marker_firstlayout);
if(resIdMain != 0){
customMarkerView.setBackgroundResource(resIdMain);
}
ImageView markerImageView = (ImageView) customMarkerView.findViewById(R.id.custom_marker_secondLayout);
if(resId != 0){
markerImageView.setImageResource(resId);
}
customMarkerView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
customMarkerView.layout(0, 0, customMarkerView.getMeasuredWidth(), customMarkerView.getMeasuredHeight());
customMarkerView.buildDrawingCache();
Bitmap returnedBitmap = Bitmap.createBitmap(customMarkerView.getMeasuredWidth(), customMarkerView.getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_IN);
Drawable drawable = customMarkerView.getBackground();
if (drawable != null)
drawable.draw(canvas);
customMarkerView.draw(canvas);
return returnedBitmap;
}
}
result:
In one of my apps I have created a circular view with multiple colors,In which I want to set click listener on each color arch
Below is the image and code for drawing that view
Custom view class code
public class CircularStatusView extends View {
private static final float DEFAULT_PORTION_WIDTH = 10;
private static final int DEFAULT_PORTION_SPACING = 5;
private static final int DEFAULT_COLOR = Color.parseColor("#D81B60");
private static final float DEFAULT_PORTIONS_COUNT = 1;
private static final float START_DEGREE =-90;
private float radius;
private float portionWidth = DEFAULT_PORTION_WIDTH;
private int portionSpacing = DEFAULT_PORTION_SPACING;
private int portionColor = DEFAULT_COLOR;
private float portionsCount = DEFAULT_PORTIONS_COUNT;
private RectF mBorderRect = new RectF();
private Paint paint;
private SparseIntArray portionToUpdateMap = new SparseIntArray();
private Context context;
public CircularStatusView(Context context) {
super(context);
init(context, null, -1);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularStatusView, defStyle, 0);
if (a != null) {
portionColor = a.getColor(R.styleable.CircularStatusView_portion_color, DEFAULT_COLOR);
portionWidth = a.getDimensionPixelSize(R.styleable.CircularStatusView_portion_width, (int) DEFAULT_PORTION_WIDTH);
portionSpacing = a.getDimensionPixelSize(R.styleable.CircularStatusView_portion_spacing, DEFAULT_PORTION_SPACING);
portionsCount = a.getInteger(R.styleable.CircularStatusView_portions_count, (int) DEFAULT_PORTIONS_COUNT);
a.recycle();
}
paint = getPaint();
}
public CircularStatusView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs, -1);
}
public CircularStatusView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBorderRect.set(calculateBounds());
radius = Math.min((mBorderRect.height() - portionWidth) / 2.0f, (mBorderRect.width() - portionWidth) / 2.0f);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float radius = this.radius;
float center_x = mBorderRect.centerX();
float center_y = mBorderRect.centerY();
final RectF oval = getOval(radius, center_x, center_y);
float degree = 360 / portionsCount;
float percent = 100 / portionsCount;
for (int i = 0; i < portionsCount; i++) {
paint.setColor(getPaintColorForIndex(i));
float startAngle = START_DEGREE + (degree * i);
canvas.drawArc(oval, (getSpacing() / 2) + startAngle, getProgressAngle(percent) - getSpacing(), false, paint);
}
}
private int getPaintColorForIndex(int i) {
if (portionToUpdateMap.indexOfKey(i) >= 0) { //if key is exists
return portionToUpdateMap.get(i);
} else {
return portionColor;
}
}
#NonNull
private RectF getOval(float radius, float center_x, float center_y) {
final RectF oval = new RectF();
oval.set(center_x - radius,
center_y - radius,
center_x + radius,
center_y + radius);
return oval;
}
#NonNull
private Paint getPaint() {
Paint paint = new Paint();
paint.setColor(portionColor);
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setStrokeWidth(portionWidth);
paint.setStrokeCap(Paint.Cap.BUTT);
return paint;
}
private int getSpacing() {
return portionsCount == 1 ? 0 : portionSpacing;
}
private RectF calculateBounds() {
int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
int sideLength = Math.min(availableWidth, availableHeight);
float left = getPaddingLeft() + (availableWidth - sideLength) / 2f;
float top = getPaddingTop() + (availableHeight - sideLength) / 2f;
return new RectF(left, top, left + sideLength, top + sideLength);
}
private float getProgressAngle(float percent) {
return percent / (float) 100 * 360;
}
public void setPortionsCount(int portionsCount) {
this.portionsCount = (float) portionsCount;
}
public void setPortionSpacing(int spacing) {
portionSpacing = spacing;
}
public void setPortionWidth(float portionWidth) {
this.portionWidth = portionWidth;
}
public void setCustomPaint(Paint paint) {
this.paint = paint;
}
public void setPortionsColor(int color) {
this.portionColor = color;
portionToUpdateMap.clear();
invalidate();
}
public void setPortionColorForIndex(int index, int color) {
if (index > portionsCount - 1) {
throw new IllegalArgumentException("Index is Bigger than the count!");
} else {
Log.d("3llomi", "adding index to map " + index);
portionToUpdateMap.put(index, color);
invalidate();
}
}
}
and in my activity class
CircularStatusView circularStatusView = findViewById(R.id.circular_status_view);
circularStatusView.setPortionsCount(6);
for (int i=0; i<AppConstants.outerCircleColors.length; i++){
circularStatusView.setPortionColorForIndex(i,Color.parseColor(AppConstants.outerCircleColors[i]));
How I can set click listener on each color arch in this view? Can someone help me out in this?
You can get the pixel from the CircularStatusView, By using OnTouchListener:
CircularStatusView view = ((CircularStatusView)v);
Bitmap bitmap = ((BitmapDrawable)view.getDrawable()).getBitmap();
int pixel = bitmap.getPixel(x,y);
You can just compare the pixel to a different color. Like...
if(pixel == Color.RED){
//It's Red Color
}
You can create an interface listener for onTouch events. Check the onTouch co-ordinates. Depending on their position you can send back the touched part index to the interface listener.
Dummy code:
public class CircularStatusView extends View {
private StatusViewTouchListener listener;
...
..
.
public void setOnClickListener(StatusViewTouchListener listener) {
this.listener = listener;
}
public interface StatusViewTouchListener {
public void onStatusViewTouch(int index);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
int indexOfTouchedColor;
// Check the touch points and determine in which color part it exists.
listener.onStatusViewTouch(indexOfTouchedColor);
return true;
}
}
Implement the listener where where you are using the view and set it to the View.
public class yourActivity extends Activity implements StatusViewTouchListener {
...
..
.
CircularStatusView circularStatusView = findViewById(R.id.circular_status_view);
circularStatusView.setPortionsCount(6);
for (int i=0; i<AppConstants.outerCircleColors.length; i++){
circularStatusView.setPortionColorForIndex(i,Color.parseColor(AppConstants.outerCircleColors[i]));
circularStatusView.setOnClickListener(this);
...
..
#Override
public void onStatusViewTouch(int index) {
// Perform your action based on the index of the color
}
}
I know android.graphics is old, but i am having trouble doing a simple stuff.
I want to draw a line animation where one View points an arrow/line into another View
First Button-------------------------------->Second Button
I have tried creating a custom View class and overriding the onDraw(Canvas c) method and then using the drawLine(startX, startY, stopX, stopY, paint) method from the Canvas Object. But i don't know which coordinates to get in order to point one View to the other View
I don't want to create a static View in the XML layout with a slim height because the View can be added dynamically by the user, which i think drawing the line dynamically is the best way.
Please help me out. Thank you!
For drawing lines between views better if all of it lays on same parent layout. For the conditions of the question (Second Button is exactly to the right of First Button) you can use custom layout like that:
public class ArrowLayout extends RelativeLayout {
public static final String PROPERTY_X = "PROPERTY_X";
public static final String PROPERTY_Y = "PROPERTY_Y";
private final static double ARROW_ANGLE = Math.PI / 6;
private final static double ARROW_SIZE = 50;
private Paint mPaint;
private boolean mDrawArrow = false;
private Point mPointFrom = new Point(); // current (during animation) arrow start point
private Point mPointTo = new Point(); // current (during animation) arrow end point
public ArrowLayout(Context context) {
super(context);
init();
}
public ArrowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ArrowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public ArrowLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
setWillNotDraw(false);
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLUE);
mPaint.setStrokeWidth(5);
}
#Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.save();
if (mDrawArrow) {
drawArrowLines(mPointFrom, mPointTo, canvas);
}
canvas.restore();
}
private Point calcPointFrom(Rect fromViewBounds, Rect toViewBounds) {
Point pointFrom = new Point();
pointFrom.x = fromViewBounds.right;
pointFrom.y = fromViewBounds.top + (fromViewBounds.bottom - fromViewBounds.top) / 2;
return pointFrom;
}
private Point calcPointTo(Rect fromViewBounds, Rect toViewBounds) {
Point pointTo = new Point();
pointTo.x = toViewBounds.left;
pointTo.y = toViewBounds.top + (toViewBounds.bottom - toViewBounds.top) / 2;
return pointTo;
}
private void drawArrowLines(Point pointFrom, Point pointTo, Canvas canvas) {
canvas.drawLine(pointFrom.x, pointFrom.y, pointTo.x, pointTo.y, mPaint);
double angle = Math.atan2(pointTo.y - pointFrom.y, pointTo.x - pointFrom.x);
int arrowX, arrowY;
arrowX = (int) (pointTo.x - ARROW_SIZE * Math.cos(angle + ARROW_ANGLE));
arrowY = (int) (pointTo.y - ARROW_SIZE * Math.sin(angle + ARROW_ANGLE));
canvas.drawLine(pointTo.x, pointTo.y, arrowX, arrowY, mPaint);
arrowX = (int) (pointTo.x - ARROW_SIZE * Math.cos(angle - ARROW_ANGLE));
arrowY = (int) (pointTo.y - ARROW_SIZE * Math.sin(angle - ARROW_ANGLE));
canvas.drawLine(pointTo.x, pointTo.y, arrowX, arrowY, mPaint);
}
public void animateArrows(int duration) {
mDrawArrow = true;
View fromView = getChildAt(0);
View toView = getChildAt(1);
// find from and to views bounds
Rect fromViewBounds = new Rect();
fromView.getDrawingRect(fromViewBounds);
offsetDescendantRectToMyCoords(fromView, fromViewBounds);
Rect toViewBounds = new Rect();
toView.getDrawingRect(toViewBounds);
offsetDescendantRectToMyCoords(toView, toViewBounds);
// calculate arrow sbegin and end points
Point pointFrom = calcPointFrom(fromViewBounds, toViewBounds);
Point pointTo = calcPointTo(fromViewBounds, toViewBounds);
ValueAnimator arrowAnimator = createArrowAnimator(pointFrom, pointTo, duration);
arrowAnimator.start();
}
private ValueAnimator createArrowAnimator(Point pointFrom, Point pointTo, int duration) {
final double angle = Math.atan2(pointTo.y - pointFrom.y, pointTo.x - pointFrom.x);
mPointFrom.x = pointFrom.x;
mPointFrom.y = pointFrom.y;
int firstX = (int) (pointFrom.x + ARROW_SIZE * Math.cos(angle));
int firstY = (int) (pointFrom.y + ARROW_SIZE * Math.sin(angle));
PropertyValuesHolder propertyX = PropertyValuesHolder.ofInt(PROPERTY_X, firstX, pointTo.x);
PropertyValuesHolder propertyY = PropertyValuesHolder.ofInt(PROPERTY_Y, firstY, pointTo.y);
ValueAnimator animator = new ValueAnimator();
animator.setValues(propertyX, propertyY);
animator.setDuration(duration);
// set other interpolator (if needed) here:
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mPointTo.x = (int) valueAnimator.getAnimatedValue(PROPERTY_X);
mPointTo.y = (int) valueAnimator.getAnimatedValue(PROPERTY_Y);
invalidate();
}
});
return animator;
}
}
with .xml layout like:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_main"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<{YOUR_PACKAGE_NAME}.ArrowLayout
android:id="#+id/arrow_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/first_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="First Button"/>
<Button
android:id="#+id/second_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Second Button"/>
</{YOUR_PACKAGE_NAME}.ArrowLayout>
</RelativeLayout>
and MainActivity.java like:
public class MainActivity extends AppCompatActivity {
private ArrowLayout mArrowLayout;
private Button mFirstButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mArrowLayout = (ArrowLayout) findViewById(R.id.arrow_layout);
mFirstButton = (Button) findViewById(R.id.first_button);
mFirstButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mArrowLayout.animateArrows(1000);
}
});
}
}
you got something like that (on First Button click):
For other cases ( Second Button is exactly to the left (or above, or below) or more complex above-right/below-left etc. of First Button) you should modify part for calculating arrow begin and end points:
private Point calcPointFrom(Rect fromViewBounds, Rect toViewBounds) {
Point pointFrom = new Point();
// Second Button above
// ----------+----------
// | |
// Second Button tho the left + First Button + Second Button tho the right
// | |
// ----------+----------
// Second Button below
//
// + - is arrow start point position
if (toViewBounds to the right of fromViewBounds){
pointFrom.x = fromViewBounds.right;
pointFrom.y = fromViewBounds.top + (fromViewBounds.bottom - fromViewBounds.top) / 2;
} else if (toViewBounds to the left of fromViewBounds) {
pointFrom.x = fromViewBounds.left;
pointFrom.y = fromViewBounds.top + (fromViewBounds.bottom - fromViewBounds.top) / 2;
} else if () {
...
}
return pointFrom;
}
Use Path and Pathmeasure for Drawing Animated Line. I have Made and test it.
Make Custom View and pass view coordinates points array to it,
public class AnimatedLine extends View {
private final Paint mPaint;
public Canvas mCanvas;
AnimationListener animationListener;
Path path;
private static long animSpeedInMs = 2000;
private static final long animMsBetweenStrokes = 100;
private long animLastUpdate;
private boolean animRunning = true;
private int animCurrentCountour;
private float animCurrentPos;
private Path animPath;
private PathMeasure animPathMeasure;
float pathLength;
float distance = 0;
float[] pos;
float[] tan;
Matrix matrix;
Bitmap bm;
public AnimatedLine(Context context) {
this(context, null);
mCanvas = new Canvas();
}
public AnimatedLine(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(15);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setColor(context.getResources().getColor(R.color.materialcolorpicker__red));
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
setLayerType(LAYER_TYPE_SOFTWARE, mPaint);
}
bm = BitmapFactory.decodeResource(getResources(), R.drawable.hand1);
bm = Bitmap.createScaledBitmap(bm, 20,20, false);
distance = 0;
pos = new float[2];
tan = new float[2];
matrix = new Matrix();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mCanvas = canvas;
if (path != null) {
if (animRunning) {
drawAnimation(mCanvas);
} else {
drawStatic(mCanvas);
}
}
}
/**
* draw Path With Animation
*
* #param time in milliseconds
*/
public void drawWithAnimation(ArrayList<PointF> points, long time,AnimationListener animationListener) {
animRunning = true;
animPathMeasure = null;
animSpeedInMs = time;
setPath(points);
setAnimationListener(animationListener);
invalidate();
}
public void setPath(ArrayList<PointF> points) {
if (points.size() < 2) {
throw new IllegalStateException("Pass atleast two points.");
}
path = new Path();
path.moveTo(points.get(0).x, points.get(0).y);
path.lineTo(points.get(1).x, points.get(1).y);
}
private void drawAnimation(Canvas canvas) {
if (animPathMeasure == null) {
// Start of animation. Set it up.
animationListener.onAnimationStarted();
animPathMeasure = new PathMeasure(path, false);
animPathMeasure.nextContour();
animPath = new Path();
animLastUpdate = System.currentTimeMillis();
animCurrentCountour = 0;
animCurrentPos = 0.0f;
pathLength = animPathMeasure.getLength();
} else {
// Get time since last frame
long now = System.currentTimeMillis();
long timeSinceLast = now - animLastUpdate;
if (animCurrentPos == 0.0f) {
timeSinceLast -= animMsBetweenStrokes;
}
if (timeSinceLast > 0) {
// Get next segment of path
float newPos = (float) (timeSinceLast) / (animSpeedInMs / pathLength) + animCurrentPos;
boolean moveTo = (animCurrentPos == 0.0f);
animPathMeasure.getSegment(animCurrentPos, newPos, animPath, moveTo);
animCurrentPos = newPos;
animLastUpdate = now;
//start draw bitmap along path
animPathMeasure.getPosTan(newPos, pos, tan);
matrix.reset();
matrix.postTranslate(pos[0], pos[1]);
canvas.drawBitmap(bm, matrix, null);
//end drawing bitmap
//take current position
animationListener.onAnimationUpdate(pos);
// If this stroke is done, move on to next
if (newPos > pathLength) {
animCurrentPos = 0.0f;
animCurrentCountour++;
boolean more = animPathMeasure.nextContour();
// Check if finished
if (!more) {
animationListener.onAnimationEnd();
animRunning = false;
}
}
}
// Draw path
canvas.drawPath(animPath, mPaint);
}
invalidate();
}
private void drawStatic(Canvas canvas) {
canvas.drawPath(path, mPaint);
canvas.drawBitmap(bm, matrix, null);
}
public void setAnimationListener(AnimationListener animationListener) {
this.animationListener = animationListener;
}
public interface AnimationListener {
void onAnimationStarted();
void onAnimationEnd();
void onAnimationUpdate(float[] pos);
}
}
I know that we can get color from bitmap.getPixel(x,y) method but I do not have x,y and I want to get x,y from given color code.
When onDraw Method will call at the first time I want to draw the line on vertical picker with default color but that time I do not have x,y so not able to call getPixel(x,y) because user-interaction does not happen.
public class VerticalSlideColorPicker extends View {
private String TAG = VerticalSlideColorPicker.class.getName();
private Paint paint;
private Paint strokePaint;
private Path path;
private Bitmap bitmap;
private int viewWidth;
private int viewHeight;
private int centerX;
private float colorPickerRadius;
private OnColorChangeListener onColorChangeListener;
private RectF colorPickerBody;
private float selectorYPos;
private int borderColor;
private float borderWidth;
private int[] colors;
private boolean cacheBitmap = true;
private Context mContext;
public VerticalSlideColorPicker(Context context) {
super(context);
mContext = context;
init();
}
public VerticalSlideColorPicker(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.VerticalSlideColorPicker,
0, 0);
try {
borderColor = a.getColor(R.styleable.VerticalSlideColorPicker_borderColor, Color.WHITE);
borderWidth = a.getDimension(R.styleable.VerticalSlideColorPicker_borderWidth, 10f);
int colorsResourceId = a.getResourceId(R.styleable.VerticalSlideColorPicker_colors, R.array.default_colors);
colors = a.getResources().getIntArray(colorsResourceId);
}
finally {
a.recycle();
}
init();
}
public VerticalSlideColorPicker(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public VerticalSlideColorPicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
setWillNotDraw(false);
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
path = new Path();
strokePaint = new Paint();
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setColor(borderColor);
strokePaint.setAntiAlias(true);
strokePaint.setStrokeWidth(borderWidth);
setDrawingCacheEnabled(true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path.addRect(colorPickerBody, Path.Direction.CW);
path.addRect(colorPickerBody, Path.Direction.CW);
canvas.drawPath(path, strokePaint);
canvas.drawPath(path, paint);
if (cacheBitmap) {
bitmap = getDrawingCache();
cacheBitmap = false;
setColor(ContextCompat.getColor(getContext(), R.color.tag_layout_border_audioyes_darkblue));
//invalidate();
}
else {
canvas.drawLine(colorPickerBody.left, selectorYPos, colorPickerBody.right, selectorYPos, strokePaint);
}
}
/**
* Set the color this view should show.
*
* #param color The color that should be selected. #argb
*/
public void setColor(int color) {
/*int[] pixels = new int[bitmap.getHeight()*bitmap.getWidth()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
for (int i=0; i<bitmap.getWidth()*5; i++)
pixels[i] = ContextCompat.getColor(getContext(), R.color.blue_picker);
bitmap.setPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());*/
/* int alpha = Color.alpha(color);
int red = Color.red(color);
int blue = Color.blue(color);
int green = Color.green(color);
float[] hsv = new float[3];
Color.RGBToHSV(red, green, blue, hsv);*/
/* selectorYPos = 584;
int selectedColor = bitmap.getPixel(viewWidth / 2, (int) selectorYPos);*/
/* this.alpha = alpha;
hue = hsv[0];
sat = hsv[1];
val = hsv[2];*/
if (onColorChangeListener != null) {
onColorChangeListener.onColorChange(color);
}
invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float yPos = Math.min(event.getY(), colorPickerBody.bottom);
android.util.Log.e(TAG, "Float :" + yPos);
yPos = Math.max(colorPickerBody.top, yPos);
android.util.Log.e(TAG, "Normal :" + yPos);
selectorYPos = yPos;
int selectedColor = bitmap.getPixel(viewWidth / 2, (int) selectorYPos);
android.util.Log.e(TAG, "Color :" + selectedColor);
if (onColorChangeListener != null) {
onColorChangeListener.onColorChange(selectedColor);
}
invalidate();
return true;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
viewWidth = w;
viewHeight = h;
centerX = viewWidth / 2;
colorPickerRadius = (viewWidth / 2) - borderWidth;
colorPickerBody = new RectF(centerX - colorPickerRadius, borderWidth + colorPickerRadius, centerX + colorPickerRadius, viewHeight - (borderWidth + colorPickerRadius));
LinearGradient gradient = new LinearGradient(colorPickerBody.left, colorPickerBody.top,
colorPickerBody.right,
colorPickerBody.bottom, colors, null, Shader.TileMode.CLAMP);
paint.setShader(gradient);
resetToDefault();
}
public void setBorderColor(int borderColor) {
this.borderColor = borderColor;
invalidate();
}
public void setBorderWidth(float borderWidth) {
this.borderWidth = borderWidth;
invalidate();
}
public void setColors(int[] colors) {
this.colors = colors;
cacheBitmap = true;
invalidate();
}
public void resetToDefault() {
selectorYPos = borderWidth + colorPickerRadius;
if (onColorChangeListener != null) {
onColorChangeListener.onColorChange(Color.TRANSPARENT);
}
invalidate();
}
public void setOnColorChangeListener(OnColorChangeListener onColorChangeListener) {
this.onColorChangeListener = onColorChangeListener;
}
}
A brute force solution could be the following:
private List<Point> getPixelswithColor(Bitmap bitmap, int colorId) {
List<Point> pixels = new ArrayList();
for (int x = 0; x < bitmap.getWidth(); x++) {
for (int y = 0; y < bitmap.getHeight(); y++) {
if (bitmap.getPixel(x, y) == colorId) {
pixels.add(new Point(x, y));
}
}
}
return pixels;
}
I have IndicationBar class that should draw rectangle with logo inside and on int value case change rectangle color. I am new to java and android so im learning everyday.
At this moment the value of int is changing in other class and i call it BluetoothChat.statusSviesos. its public static int. Do i need to create interface Listener or how can i run private void Sviesos() every time int is changed? It runs only once in start.
public class IndicationBar extends View {
private static final String TAG = IndicationBar.class.getSimpleName();
// drawing tools
private RectF Rect;
private Paint rectPaint;
private Paint rimCirclePaint;
private RectF faceRect;
private Bitmap faceTexture;
private Paint facePaint;
private Paint rimShadowPaint;
private Paint titlePaint;
private Path titlePath;
private Paint logoPaint;
private Bitmap logo;
private Matrix logoMatrix;
private float logoScale;
private Paint backgroundPaint;
// end drawing tools
private Bitmap background; // holds the cached static part
public IndicationBar(Context context) {
super(context);
init();
}
public IndicationBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public IndicationBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
Parcelable superState = bundle.getParcelable("superState");
super.onRestoreInstanceState(superState);
}
private void init() {
initDrawingTools();
}
// private String getTitle() {
// return "DANCER";
// }
private void Sviesos(){
//Rect = new RectF(0.1f, 0.1f, 0.9f, 0.9f);
//rectPaint = new Paint();
//valueSviesos = BluetoothChat.statusSviesos;
switch(BluetoothChat.statusSviesos){
case 0 : rectPaint.setColor(Color.parseColor("#1BA1E2"));
break;
case 1 : rectPaint.setColor(Color.parseColor("#A05000"));
break;
case 2 : rectPaint.setColor(Color.parseColor("#E671B8"));
break;
case 3 : rectPaint.setColor(Color.parseColor("#F09609"));
break;
case 4 : rectPaint.setColor(Color.parseColor("#1BA1E2"));
break;
}
//rectPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
}
private void initDrawingTools() {
Rect = new RectF(0.1f, 0.1f, 0.9f, 0.9f);
rectPaint = new Paint();
rectPaint.setColor(Color.parseColor("#8CBF26"));
rectPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
Sviesos();
rimCirclePaint = new Paint();
rimCirclePaint.setAntiAlias(true);
rimCirclePaint.setStyle(Paint.Style.STROKE);
rimCirclePaint.setColor(Color.argb(0x4f, 0x33, 0x36, 0x33));
rimCirclePaint.setStrokeWidth(0.005f);
float rimSize = 0.02f;
faceRect = new RectF();
faceRect.set(Rect.left + rimSize, Rect.top + rimSize,
Rect.right - rimSize, Rect.bottom - rimSize);
faceTexture = BitmapFactory.decodeResource(getContext().getResources(),
R.drawable.plastic);
BitmapShader paperShader = new BitmapShader(faceTexture,
Shader.TileMode.MIRROR,
Shader.TileMode.MIRROR);
Matrix paperMatrix = new Matrix();
facePaint = new Paint();
facePaint.setFilterBitmap(true);
paperMatrix.setScale(1.0f / faceTexture.getWidth(),
1.0f / faceTexture.getHeight());
paperShader.setLocalMatrix(paperMatrix);
facePaint.setStyle(Paint.Style.FILL);
facePaint.setShader(paperShader);
rimShadowPaint = new Paint();
rimShadowPaint.setShader(new RadialGradient(0.5f, 0.5f, faceRect.width() / 2.0f,
new int[] { 0x00000000, 0x00000500, 0x50000500 },
new float[] { 0.96f, 0.96f, 0.99f },
Shader.TileMode.MIRROR));
rimShadowPaint.setStyle(Paint.Style.FILL);
titlePaint = new Paint();
titlePaint.setColor(Color.parseColor("#1BA1E2"));
titlePaint.setAntiAlias(true);
titlePaint.setTypeface(Typeface.DEFAULT_BOLD);
titlePaint.setTextAlign(Paint.Align.CENTER);
titlePaint.setTextSize(0.09f);
titlePaint.setTextScaleX(0.9f);
titlePath = new Path();
titlePath.addArc(new RectF(0.24f, 0.24f, 0.76f, 0.76f), -180.0f, -180.0f);
logoPaint = new Paint();
logoPaint.setFilterBitmap(true);
logo = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.sviesos);
logoMatrix = new Matrix();
logoScale = (1.0f / logo.getWidth()) * 0.3f;;
logoMatrix.setScale(logoScale, logoScale);
backgroundPaint = new Paint();
backgroundPaint.setFilterBitmap(true);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d(TAG, "Width spec: " + MeasureSpec.toString(widthMeasureSpec));
Log.d(TAG, "Height spec: " + MeasureSpec.toString(heightMeasureSpec));
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int chosenWidth = chooseDimension(widthMode, widthSize);
int chosenHeight = chooseDimension(heightMode, heightSize);
int chosenDimension = Math.min(chosenWidth, chosenHeight);
setMeasuredDimension(chosenDimension, chosenDimension);
}
private int chooseDimension(int mode, int size) {
if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) {
return size;
} else { // (mode == MeasureSpec.UNSPECIFIED)
return getPreferredSize();
}
}
// in case there is no size specified
private int getPreferredSize() {
return 300;
}
private void drawRect(Canvas canvas) {
// first, draw the metallic body
canvas.drawRect(Rect, rectPaint);
// now the outer rim circle
//canvas.drawOval(rimRect, rimCirclePaint);
}
// private void drawFace(Canvas canvas) {
// canvas.drawOval(faceRect, facePaint);
// // draw the inner rim circle
// canvas.drawOval(faceRect, rimCirclePaint);
// // draw the rim shadow inside the face
// canvas.drawOval(faceRect, rimShadowPaint);
// }
private void drawBackground(Canvas canvas) {
if (background == null) {
Log.w(TAG, "Background not created");
} else {
canvas.drawBitmap(background, 0, 0, backgroundPaint);
}
}
#Override
protected void onDraw(Canvas canvas) {
drawBackground(canvas);
float scale = (float) getWidth();
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(scale, scale);
drawLogo(canvas);
canvas.restore();
}
private void drawLogo(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(0.5f - logo.getWidth() * logoScale / 2.0f,
0.5f - logo.getHeight() * logoScale / 2.0f);
canvas.drawBitmap(logo, logoMatrix, logoPaint);
canvas.restore();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.d(TAG, "Size changed to " + w + "x" + h);
regenerateBackground();
}
private void regenerateBackground() {
// free the old bitmap
Sviesos();
if (background != null) {
background.recycle();
}
background = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas backgroundCanvas = new Canvas(background);
float scale = (float) getWidth();
backgroundCanvas.scale(scale, scale);
drawRect(backgroundCanvas);
}
}
Use the Observer pattern for this. Change the BluetoothChat
public class BluetoothChat {
private static int statusSviesos;
//the list of observers
private static List<Observer> observerList;
//adds an observer to observe statusSciesos
public static void addStatusSviesosObserver(Observer observer) {
observerList.add(observer);
}
//getter function returns the value
public static int getStatusSviesos(){
return statusSviesos;
}
//setter function sets the value and notifies observer
public static void setStatusSviesos(int statusSviesos){
BluetoothChat.statusSviesos=statusSviesos;
for(Observer current: observerList){
current.notifyChange(statusSviesos);
}
}
public static interface Observer {
public void notifyChange(int newStatus);
}
...
Then create an Observer in the IndicationBar and add it to the BluetoothChat:
Observer observer = new Observer() {
#Override
public void notifyChange(int newStatus) {
Sviesos();
}
};
BluetoothChat.addStatusSviesosObserver(observer);
This is a raw implementation of the Observer pattern. There should be a removeObserver-method too and it is not thread-safe. There is a default implementations ready in Java (Observer-class and Observable-class) and there are alternative implementations like PropertyChangeObserver. But for your current use case this should do the job. Also read Wikipedia and Vogellas tutorial
General tips:
Does BluetoothChat's attribute really has to be static? I recommend you to use static as less as possible. Better create an Object once and pass it around instead. You can search for "global state" and why to avoid it for further information.
You could create an array of Colors (or Color-strings like "#F09609") and access it with the int you get to get rid of the switch-statement.
Try to apply code style conventions everywhere, method names and variables should always start with a small letter (except constants which are ALL_BIG) and should be descriptive.