Related
In android I have create custom view.I have first drawn circle and now I want to draw a line angle wise within a circle. I want like this with animation.
https://drive.google.com/file/d/1Qx0MBu-77JIlQTByqGTyD-KtGKOB8naG/view?usp=sharing
I have used canvas to draw circle and lines.I have taken viewpager.If I swipe viewpager then pie graphics will rotate.
What I have done uptill now. When animating it's always start from zero:
https://drive.google.com/file/d/12mmAUOeY77jAlj_GmM3Ymcx5m34vli3X/view?usp=sharing
I have done below code:
public class PieView : View
{
int w, h, pl, pr, pt, pb, usableWidth, usableHeight, radius, cx, cy, lineLenght;
Paint paint;
public Canvas canvas;
public float firstLineangle = 0;
public float secondLineangle = 40;
public float thirdLineangle = 120;
float currentAngle,maxAngle;
public override void Draw(Canvas canvas)
{
base.Draw(canvas);
w = Width;
h = Height;
pl = PaddingLeft;
pr = PaddingRight;
pt = PaddingTop;
pb = PaddingBottom;
this.canvas = canvas;
usableWidth = w - (pl + pr);
usableHeight = h - (pt + pb);
radius = Math.Min(usableWidth, usableHeight) / 2;
cx = pl + (usableWidth / 2);
cy = pt + (usableHeight / 2);
lineLenght = radius - (pl * 2) - (pr * 2);
paint = new Paint();
paint.Color = Android.Graphics.Color.White;
paint.SetStyle(Paint.Style.Stroke);
paint.StrokeWidth = 5;
canvas.DrawCircle(cx, cy, radius - 5, paint);
Drawline(canvas, firstLineangle);
Drawline(canvas, secondLineangle);
Drawline(canvas, thirdLineangle);
PostInvalidateDelayed(500);
Invalidate();
}
public void Drawline(Canvas canvas, float angle)
{
float displacedAngle = angle - 90;
float x = cx + ((float)Math.Cos(degreesToRadians(displacedAngle)) * (radius - 5)); //convert angle to radians for x and y coordinates
float y = cy + ((float)Math.Sin(degreesToRadians(displacedAngle)) * (radius - 5));
canvas.DrawLine(cx, cy, x, y, paint); //draw a line from center point back to the point
}
public double degreesToRadians(double degrees)
{
return (degrees * Math.PI) / 180;
}
}
public class PieAnimation : Android.Views.Animations.Animation
{
private PieView pieView;
private float firstLineangle;
private float secondLineangle;
private float thirdLineangle;
public PieAnimation(PieView pieView, float firstLineangle,float secondLineangle,float thirdLineangle)
{
this.pieView = pieView;
this.firstLineangle = firstLineangle;
this.secondLineangle = secondLineangle;
this.thirdLineangle = thirdLineangle;
}
protected override void ApplyTransformation(float interpolatedTime, Transformation t)
{
pieView.firstLineangle = 0 + ((firstLineangle) * interpolatedTime);
pieView.secondLineangle = 0 + ((secondLineangle) * interpolatedTime);
pieView.thirdLineangle = 0 + ((thirdLineangle) * interpolatedTime);
pieView.RequestLayout();
}
}
public class TourPager : Java.Lang.Object, ViewPager.IOnPageChangeListener, ViewPager.IPageTransformer
{
private ViewPager mViewPager;
private float mLastOffset;
public TourView _context;
public TourPager(ViewPager viewpager, TourView context)
{
mViewPager = viewpager;
viewpager.AddOnPageChangeListener(this);
_context = context;
}
public void OnPageSelected(int position)
{
if (position == 0)
{
PieAnimation animation = new PieAnimation(_context._pieView, 0, 40, 120);
animation.Duration = (1000);
_context._pieView.StartAnimation(animation);
}
if (position==1)
{
PieAnimation animation = new PieAnimation(_context._pieView, 100, 140, 200);
animation.Duration=(1000);
_context._pieView.StartAnimation(animation);
}
if(position==2)
{
PieAnimation animation = new PieAnimation(_context._pieView, 180, 270, 10);
animation.Duration = (1000);
_context._pieView.StartAnimation(animation);
}
}
There is running GIF.
There is PieView.cs.
public class PieView:View
{
int w, h, pl, pr, pt, pb, usableWidth, usableHeight, radius, cx, cy, lineLenght;
int handTruncation, hourHandTruncation = 0;
Paint paint;
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
Rect rect = new Rect();
public PieView(Context context) : base(context)
{
}
public PieView(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
public PieView(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
{
}
public PieView(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
{
}
public override void Draw(Canvas canvas)
{
base.Draw(canvas);
w = Width;
h = Height;
pl = PaddingLeft+10;
pr = PaddingRight+10;
pt = PaddingTop+10;
pb = PaddingBottom+10;
usableWidth = w - (pl + pr);
usableHeight = h - (pt + pb);
radius = Math.Min(usableWidth, usableHeight) / 2;
cx = pl + (usableWidth / 2);
cy = pt + (usableHeight / 2);
int min = Math.Min(usableWidth, usableHeight);
handTruncation = min / 20;
hourHandTruncation = min / 7;
lineLenght = radius - (pl * 2) - (pr * 2);
paint = new Paint();
paint.Color = Android.Graphics.Color.White;
paint.SetStyle(Paint.Style.Stroke);
paint.StrokeWidth = 5;
canvas.DrawCircle(cx, cy, radius , paint);
drawNumeral(canvas);
drawHands(canvas);
PostInvalidateDelayed(200);
Invalidate();
}
private void drawHands(Canvas canvas)
{
Calendar c = Calendar.Instance;
float hour = c.Get(CalendarField.HourOfDay);
hour = hour > 12 ? hour - 12 : hour;
drawHand1(canvas, (hour + c.Get(CalendarField.Minute) / 60) * 5f,true);
drawHand1(canvas, c.Get(CalendarField.Minute),false);
drawHand1(canvas, c.Get(CalendarField.Second),false);
}
private void drawNumeral(Canvas canvas)
{
paint.TextSize=50;
foreach (var number in numbers)
{
string tmp = number.ToString();
paint.GetTextBounds( tmp, 0, tmp.Length, rect); //getTextBounds(tmp, 0, tmp.length(), rect);
double angle = Math.PI / 6 * (number - 3);
int x = (int)(w / 2 + Math.Cos(angle) * radius - rect.Width() / 2);
int y = (int)(h / 2 + Math.Sin(angle) * radius + rect.Height() / 2);
canvas.DrawText(tmp, x, y, paint);
}
}
private void drawHand1(Canvas canvas, double loc, bool isHour)
{
double angle = Math.PI * loc / 30 - Math.PI / 2;
int handRadius = isHour ? radius - handTruncation - hourHandTruncation : radius - handTruncation;
canvas.DrawLine(Width / 2, Height / 2,
(float)(Width / 2 + Math.Cos(angle) * handRadius),
(float)(Height / 2 + Math.Sin(angle) * handRadius),
paint);
}
}
You can use it in MainActivity.cs
RelativeLayout relativeLayout1 = FindViewById<RelativeLayout>
(Resource.Id.relativeLayout1);
relativeLayout1.SetBackgroundColor(Color.Black);
AddContentView(new PieView(this),new ViewGroup.LayoutParams(-1,-1));
How to give hexagon shape to ImageView . Is it possible to do in same way ? If so then how. If this is not possible through this then how this could be achieved ?
<shape xmlns:android="http//schemas.android.com/apk/res/android"
android:shape="hexagon">
<solid android:color="#ffffffff" />
<size android:width="60dp"
android:height="40dp" />
</shape>
Screenshot
Here I can't do masking image because I can not detect which portion of bitmap I should crop to get hexagon shape bitmap. So I am looking for the answer to give hexagon shape to ImageView
Try this View. You might want to adjust it for your specific needs, but it draws a hexagon mask with a border on top of a view. The background resource goes below the mask.
The result:
The code:
HexagonMaskView.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Path;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.View;
public class HexagonMaskView extends View {
private Path hexagonPath;
private Path hexagonBorderPath;
private float radius;
private float width, height;
private int maskColor;
public HexagonMaskView(Context context) {
super(context);
init();
}
public HexagonMaskView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public HexagonMaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
hexagonPath = new Path();
hexagonBorderPath = new Path();
maskColor = 0xFF01FF77;
}
public void setRadius(float r) {
this.radius = r;
calculatePath();
}
public void setMaskColor(int color) {
this.maskColor = color;
invalidate();
}
private void calculatePath() {
float triangleHeight = (float) (Math.sqrt(3) * radius / 2);
float centerX = width/2;
float centerY = height/2;
hexagonPath.moveTo(centerX, centerY + radius);
hexagonPath.lineTo(centerX - triangleHeight, centerY + radius/2);
hexagonPath.lineTo(centerX - triangleHeight, centerY - radius/2);
hexagonPath.lineTo(centerX, centerY - radius);
hexagonPath.lineTo(centerX + triangleHeight, centerY - radius/2);
hexagonPath.lineTo(centerX + triangleHeight, centerY + radius/2);
hexagonPath.moveTo(centerX, centerY + radius);
float radiusBorder = radius - 5;
float triangleBorderHeight = (float) (Math.sqrt(3) * radiusBorder / 2);
hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY + radiusBorder/2);
hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY - radiusBorder/2);
hexagonBorderPath.lineTo(centerX, centerY - radiusBorder);
hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY - radiusBorder/2);
hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY + radiusBorder/2);
hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
invalidate();
}
#Override
public void onDraw(Canvas c){
super.onDraw(c);
c.clipPath(hexagonBorderPath, Region.Op.DIFFERENCE);
c.drawColor(Color.WHITE);
c.save();
c.clipPath(hexagonPath, Region.Op.DIFFERENCE);
c.drawColor(maskColor);
c.save();
}
// getting the view size and default radius
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
radius = height / 2 - 10;
calculatePath();
}
}
Update 29.07.2016
A better way to only clip the source image without painting the whole view's background. Switched to an ImageView as a base class to benefit from the scaleType. I also did some code refactoring.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Region;
import android.util.AttributeSet;
import android.widget.ImageView;
public class HexagonMaskView extends ImageView {
private Path hexagonPath;
private Path hexagonBorderPath;
private Paint mBorderPaint;
public HexagonMaskView(Context context) {
super(context);
init();
}
public HexagonMaskView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public HexagonMaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
this.hexagonPath = new Path();
this.hexagonBorderPath = new Path();
this.mBorderPaint = new Paint();
this.mBorderPaint.setColor(Color.WHITE);
this.mBorderPaint.setStrokeCap(Paint.Cap.ROUND);
this.mBorderPaint.setStrokeWidth(50f);
this.mBorderPaint.setStyle(Paint.Style.STROKE);
}
public void setRadius(float radius) {
calculatePath(radius);
}
public void setBorderColor(int color) {
this.mBorderPaint.setColor(color);
invalidate();
}
private void calculatePath(float radius) {
float halfRadius = radius / 2f;
float triangleHeight = (float) (Math.sqrt(3.0) * halfRadius);
float centerX = getMeasuredWidth() / 2f;
float centerY = getMeasuredHeight() / 2f;
this.hexagonPath.reset();
this.hexagonPath.moveTo(centerX, centerY + radius);
this.hexagonPath.lineTo(centerX - triangleHeight, centerY + halfRadius);
this.hexagonPath.lineTo(centerX - triangleHeight, centerY - halfRadius);
this.hexagonPath.lineTo(centerX, centerY - radius);
this.hexagonPath.lineTo(centerX + triangleHeight, centerY - halfRadius);
this.hexagonPath.lineTo(centerX + triangleHeight, centerY + halfRadius);
this.hexagonPath.close();
float radiusBorder = radius - 5f;
float halfRadiusBorder = radiusBorder / 2f;
float triangleBorderHeight = (float) (Math.sqrt(3.0) * halfRadiusBorder);
this.hexagonBorderPath.reset();
this.hexagonBorderPath.moveTo(centerX, centerY + radiusBorder);
this.hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY + halfRadiusBorder);
this.hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY - halfRadiusBorder);
this.hexagonBorderPath.lineTo(centerX, centerY - radiusBorder);
this.hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY - halfRadiusBorder);
this.hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY + halfRadiusBorder);
this.hexagonBorderPath.close();
invalidate();
}
#Override
public void onDraw(Canvas c) {
c.drawPath(hexagonBorderPath, mBorderPaint);
c.clipPath(hexagonPath, Region.Op.INTERSECT);
c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
super.onDraw(c);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
calculatePath(Math.min(width / 2f, height / 2f) - 10f);
}
}
Example layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:background="#android:color/holo_green_dark">
<com.scelus.hexagonmaskimproved.HexagonMaskView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/bear"
android:background="#android:color/holo_green_light"/>
</RelativeLayout>
Here is my working code for this, it supports shadows to:
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class HexagonImageView extends ImageView {
private Path hexagonPath;
private Path hexagonBorderPath;
private float radius;
private Bitmap image;
private int viewWidth;
private int viewHeight;
private Paint paint;
private BitmapShader shader;
private Paint paintBorder;
private int borderWidth = 4;
public HexagonImageView(Context context) {
super(context);
setup();
}
public HexagonImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setup();
}
public HexagonImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setup();
}
private void setup() {
paint = new Paint();
paint.setAntiAlias(true);
paintBorder = new Paint();
setBorderColor(Color.WHITE);
paintBorder.setAntiAlias(true);
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 1.0f, 1.0f, Color.BLACK);
hexagonPath = new Path();
hexagonBorderPath = new Path();
}
public void setRadius(float r) {
this.radius = r;
calculatePath();
}
public void setBorderWidth(int borderWidth) {
this.borderWidth = borderWidth;
this.invalidate();
}
public void setBorderColor(int borderColor) {
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
private void calculatePath() {
float triangleHeight = (float) (Math.sqrt(3) * radius / 2);
float centerX = viewWidth/2;
float centerY = viewHeight/2;
hexagonBorderPath.moveTo(centerX, centerY + radius);
hexagonBorderPath.lineTo(centerX - triangleHeight, centerY + radius/2);
hexagonBorderPath.lineTo(centerX - triangleHeight, centerY - radius/2);
hexagonBorderPath.lineTo(centerX, centerY - radius);
hexagonBorderPath.lineTo(centerX + triangleHeight, centerY - radius/2);
hexagonBorderPath.lineTo(centerX + triangleHeight, centerY + radius/2);
hexagonBorderPath.moveTo(centerX, centerY + radius);
float radiusBorder = radius - borderWidth;
float triangleBorderHeight = (float) (Math.sqrt(3) * radiusBorder / 2);
hexagonPath.moveTo(centerX, centerY + radiusBorder);
hexagonPath.lineTo(centerX - triangleBorderHeight, centerY + radiusBorder/2);
hexagonPath.lineTo(centerX - triangleBorderHeight, centerY - radiusBorder/2);
hexagonPath.lineTo(centerX, centerY - radiusBorder);
hexagonPath.lineTo(centerX + triangleBorderHeight, centerY - radiusBorder/2);
hexagonPath.lineTo(centerX + triangleBorderHeight, centerY + radiusBorder/2);
hexagonPath.moveTo(centerX, centerY + radiusBorder);
invalidate();
}
private void loadBitmap() {
BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable();
if (bitmapDrawable != null)
image = bitmapDrawable.getBitmap();
}
#SuppressLint("DrawAllocation")
#Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
loadBitmap();
// init shader
if (image != null) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvas.getWidth(), canvas.getHeight(), false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
canvas.drawPath(hexagonBorderPath, paintBorder);
canvas.drawPath(hexagonPath, paint);
}
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec, widthMeasureSpec);
viewWidth = width - (borderWidth * 2);
viewHeight = height - (borderWidth * 2);
radius = height / 2 - borderWidth;
calculatePath();
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}
else {
result = viewWidth;
}
return result;
}
private int measureHeight(int measureSpecHeight, int measureSpecWidth) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}
else {
result = viewHeight;
}
return (result + 2);
}
}
There are a couple things you can try:
You might want to try drawing a 9patch in top of your image.
There's also this short tuto by Romain Guy : http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
BitmapShader shader;
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);
RectF rect = new RectF(0.0f, 0.0f, width, height);
// rect contains the bounds of the shape
// radius is the radius in pixels of the rounded corners
// paint contains the shader that will texture the shape
canvas.drawRoundRect(rect, radius, radius, paint);
Instead of using drawRoundRect() method of canvas, you may try using drawPath() to get the desired shape.
Hope this puts you on the right direction.
See this example which is creating triangle so you can get logic from it :)
http://looksok.wordpress.com/2013/08/24/android-triangle-arrow-defined-as-an-xml-shape/
Another solution I found but not tested so try this also
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv = (TextView) findViewById(R.id.text);
Path path = new Path();
float stdW = 100;
float stdH = 100;
float w3 = stdW / 3;
float h2 = stdH / 2;
path.moveTo(0, h2);
h2 -= 6 / 2;
path.rLineTo(w3, -h2); path.rLineTo(w3, 0); path.rLineTo(w3, h2);
path.rLineTo(-w3, h2); path.rLineTo(-w3, 0); path.rLineTo(-w3, -h2);
Shape s = new PathShape(path, stdW, stdH);
ShapeDrawable d = new ShapeDrawable(s);
Paint p = d.getPaint();
p.setColor(0xffeeeeee);
p.setStyle(Style.STROKE);
p.setStrokeWidth(6);
tv.setBackgroundDrawable(d);
}
Source: Google group
Third solution - This might be useful library
PathDrawable is a Drawable that draws simple shapes using Path object.
Its Late to relpy.. But Hope it will help someone...
public Bitmap getHexagonShape(Bitmap scaleBitmapImage) {
// TODO Auto-generated method stub
int targetWidth = 200;
int targetHeight =200;
Bitmap targetBitmap = Bitmap.createBitmap(targetWidth,
targetHeight,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
float stdW = 200;
float stdH = 200;
float w3 =stdW / 2;
float h2 = stdH / 2;
float radius=stdH/2-10;
float triangleHeight = (float) (Math.sqrt(3) * radius / 2);
float centerX = stdW/2;
float centerY = stdH/2;
path.moveTo(centerX, centerY + radius);
path.lineTo(centerX - triangleHeight, centerY + radius/2);
path.lineTo(centerX - triangleHeight, centerY - radius/2);
path.lineTo(centerX, centerY - radius);
path.lineTo(centerX + triangleHeight, centerY - radius/2);
path.lineTo(centerX + triangleHeight, centerY + radius/2);
path.moveTo(centerX, centerY + radius);
canvas.clipPath(path);
Bitmap sourceBitmap = scaleBitmapImage;
canvas.drawBitmap(sourceBitmap,
new Rect(0, 0, sourceBitmap.getWidth(),
sourceBitmap.getHeight()),
new Rect(0, 0, targetWidth,
targetHeight), null);
return targetBitmap;
}
public static Bitmap drawableToBitmap (Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable)drawable).getBitmap();
}
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
Call this where you want to use
Drawable drawable = getResources().getDrawable( R.drawable.placeholder );
Bitmap b=getHexagonShape(drawableToBitmap(drawable));
img=(ImageView)findViewById(R.id.imageView);
img.setImageBitmap(b);
The function below reads your image as input bitmap and returns a bitmap which is hexagon in shape
public Bitmap getHexagonShape(Bitmap scaleBitmapImage) {
// TODO Auto-generated method stub
int targetWidth = 600;
int targetHeight = 600;
Bitmap targetBitmap = Bitmap.createBitmap(targetWidth,
targetHeight,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
float stdW = 300;
float stdH = 300;
float w3 =stdW / 2;
float h2 = stdH / 2;
path.moveTo(0, (float) (h2*Math.sqrt(3)/2));
path.rLineTo(w3/2, -(float) (h2*Math.sqrt(3)/2)); path.rLineTo(w3, 0); path.rLineTo(w3/2, (float) (h2*Math.sqrt(3)/2));
path.rLineTo(-w3/2, (float) (h2*Math.sqrt(3)/2)); path.rLineTo(-w3, 0); path.rLineTo(-w3/2, -(float) (h2*Math.sqrt(3)/2));
canvas.clipPath(path);
Bitmap sourceBitmap = scaleBitmapImage;
canvas.drawBitmap(sourceBitmap,
new Rect(0, 0, sourceBitmap.getWidth(),
sourceBitmap.getHeight()),
new Rect(0, 0, targetWidth,
targetHeight), null);
return targetBitmap;
}
I don't know if the OP got the answer he was looking for, but here goes.
I've create a custom view, that extends ImageView, that will do the job for you a bit better.
The answer here just creates a maks inside the ImageView and forces you to set the picture as the background
My view lets you set the image like a standard bitmap, it handles CenterCrop and scaling of the image.
It actually sets the mask outside instead, and with the same border plus drop shadow.
And if that not enough, you can easily create custom shapes to render, just be extending the RenderShape-class. (4 shapes are included in the library: Circle, Triangle, Hexagon and Octagon)
Have a look at my github
Cheers
I've solved it using this code:
private Bitmap getHexagoneCroppedBitmap(Bitmap bitmap, int radius) {
Bitmap finalBitmap;
if (bitmap.getWidth() != radius || bitmap.getHeight() != radius)
finalBitmap = Bitmap.createScaledBitmap(bitmap, radius, radius,
false);
else
finalBitmap = bitmap;
Bitmap output = Bitmap.createBitmap(finalBitmap.getWidth(),
finalBitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
Paint paint = new Paint();
final Rect rect = new Rect(0, 0, finalBitmap.getWidth(),
finalBitmap.getHeight());
Point point1_draw = new Point(75, 0);
Point point2_draw = new Point(0, 50);
Point point3_draw = new Point(0, 100);
Point point4_draw = new Point(75, 150);
Point point5_draw = new Point(150, 100);
Point point6_draw = new Point(150, 50);
Path path = new Path();
path.moveTo(point1_draw.x, point1_draw.y);
path.lineTo(point2_draw.x, point2_draw.y);
path.lineTo(point3_draw.x, point3_draw.y);
path.lineTo(point4_draw.x, point4_draw.y);
path.lineTo(point5_draw.x, point5_draw.y);
path.lineTo(point6_draw.x, point6_draw.y);
path.close();
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#BAB399"));
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(finalBitmap, rect, rect, paint);
return output;
}
You can use the Android Shape ImageView by siamed.
https://github.com/siyamed/android-shape-imageview
<com.github.siyamed.shapeimageview.HexagonImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
android:src="#drawable/neo"
app:siBorderWidth="8dp"
app:siBorderColor="#color/darkgray"/>
Please read the documentation on github, lots of options are available.
I am currently trying to create a meter that can be adjusted in the percentage of fill. The problem I have is I'm not good at math at all. I want to start drawing an arc in the 'north' (first image), as opposed to a normal arc having its 0 deg point in the 'east' (as shown in second image).
I want to be able to increase the blue area in image 1 in size (angle) by dragging/touching it along the screen. Now these are things I am able to do in some kind of fashion now. The real problem I am facing is this:
I use the following code to draw the blue area:
mStart = -90;
int degree = (int)((theta + Math.PI) * 180 / Math.PI);
mSweep = degree;
RectF mOvals = new RectF(c.x - outerRadius + circleThickness, c.y - outerRadius + circleThickness, c.x + outerRadius - circleThickness, c.y + outerRadius - circleThickness );
mArcSetLevel = new Path();
if(mArcSetLevel != null ) {
canvas.drawArc(mOvals, mStart, mSweep, true, arcPaint);
}
Setting the start at -90 makes it start 90 deg earlier. To track the angle of the touch I use this formula, but this is where it goes wrong:
int py = (int)event.getY() - c.y;
int px = (int)event.getX() - c.x;
theta = (float) ((float) Math.atan2(py, px) - (Math.PI / 2)); // - Math.PI / 2 to correct -90 start
When I go further than exactly 270 degrees the blue area gets reset and draws itself from north to west in a much smaller angle (because of the 'false' start of -90, shown in third image). My math skills are simply not good enough for me to be able to solve this, although I can think of why it is happening I cannot seem to find the solution.
The (very messy) code to the entire view I made is as follows:
private Canvas canvas;
//Canvas width and height
private int h = -1;
private int w = -1;
//circle properties
private Paint paint;
private Paint arcPaint;
private Path circle;
private Point c;
private int outerRadius;
private int circleThickness = 20;
//point click in wheel
private float theta = 0;
private float mStart;
private float mSweep;
private Paint mBgPaints = new Paint();
private Path mArcSetLevel;
int padding = 10;
OnMeterWheelChangeListener onMeterWheelChangeListener = null;
public MeterWheel(Context context){
super(context);
initCircleSeekBar();
}
public MeterWheel(Context context, AttributeSet attrs) {
super(context, attrs);
initCircleSeekBar();
}
private void initCircleSeekBar() {
canvas = new Canvas();
circle = new Path();
paint = new Paint();
arcPaint = new Paint();
c = new Point();
mBgPaints.setAntiAlias(true);
mBgPaints.setStyle(Paint.Style.FILL);
mBgPaints.setColor(0x88FF0000);
mBgPaints.setStrokeWidth(0.5f);
mArcSetLevel = new Path();
this.draw(canvas);
}
#Override
protected void onSizeChanged(int width, int height, int oldw, int oldh) {
// TODO Auto-generated method stub
super.onSizeChanged(width, height, oldw, oldh);
w = width;
h = height;
Log.i("POWERWHEEL", String.valueOf(w) + " " + String.valueOf(h));
c.set(w/2, h/2);
drawCircle();
}
private void drawCircle() {
outerRadius = Math.min(h,w)/2;
circleThickness = (int) (outerRadius*0.15);
circle.addArc(new RectF(c.x - outerRadius + circleThickness/2, c.y - outerRadius + circleThickness/2, c.x + outerRadius - circleThickness/2, c.y + outerRadius - circleThickness/2 ), 0, 360);
circle.moveTo(c.x, c.y);
//paint.setShader(new SweepGradient(w/2,h/2, colourarry, null));
paint.setColor(Color.GRAY);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(circleThickness);
paint.setAntiAlias(true);
arcPaint.setColor(Color.BLUE);
arcPaint.setStyle(Style.FILL);
arcPaint.setStrokeWidth(circleThickness);
arcPaint.setAntiAlias(true);
}
#SuppressLint("DrawAllocation")
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if(circle != null){
//draw circle
canvas.drawPath(circle, paint);
mStart = -90;
int degree = (int)((theta + Math.PI) * 180 / Math.PI);
Log.d("POWERWHEEL", "" + degree);
mSweep = degree;
RectF mOvals = new RectF(c.x - outerRadius + circleThickness, c.y - outerRadius + circleThickness, c.x + outerRadius - circleThickness, c.y + outerRadius - circleThickness );
mArcSetLevel = new Path();
if(mArcSetLevel != null ) {
canvas.drawArc(mOvals, mStart, mSweep, true, arcPaint);
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setPressed(true);
onStartTrackingTouch(event);
trackTouchEvent(event);
break;
case MotionEvent.ACTION_MOVE:
trackTouchEvent(event);
break;
case MotionEvent.ACTION_UP:
trackTouchEvent(event);
onStopTrackingTouch();
setPressed(false);
invalidate();
break;
case MotionEvent.ACTION_CANCEL:
onStopTrackingTouch();
setPressed(false);
invalidate();
break;
}
return true;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width,height);
}
private void onStartTrackingTouch(MotionEvent event) {
}
private void onStopTrackingTouch() {
}
private void trackTouchEvent(MotionEvent event) {
int py = (int)event.getY() - c.y;
int px = (int)event.getX() - c.x;
theta = (float) ((float) Math.atan2(py, px) - (Math.PI / 2));
Log.d("POWERWHEEL", "theta: " + theta);
this.invalidate();
}
public void setSize(int x, int y){
h = y;
w = x;
}
public void setCirleThickness(int t){
circleThickness = t;
}
public void setOnMeterWheelChangeListener (OnMeterWheelChangeListener listener) {
onMeterWheelChangeListener = listener;
}
public interface OnMeterWheelChangeListener{
public void onStartTrackingTouch (MeterWheel colourWheel);
public void onStopTrackingTouch (MeterWheel colourWheel);
}
Thanks a million in advance!
When calculating theta, you use atan2 which returns the angle in +/- pi. So when being in the upper left quadrant it will return a value in the range -pi/2 to -pi (asuming y is positive downwards and x is positve rightwards). You substract pi/2 directly with gives a range of -pi to -3pi/2. In onDraw you then add pi again (confusing) giving a range of 0 to -pi/2 of the sweep for this quadrant. This means it will paint the arc 0 to pi/2 (or 0 to 90 degrees) counterclockwise from your starting position at the top. You must make sure your sweep always keeps in the range 0 to pi. Nicest solution is to shift the coordinates by -pi/2, so that instead of Math.atan2(py, px), you do Math.atan2(px, -py) and then if theta is negative you add 2*pi. Something like (I don't write android)
theta = (float) Math.atan2(px, -py);
if (theta < 0) theta += 2 * Math.PI;
and then in onDraw
int degree = (int)(theta * 180 / Math.PI);
Log.d("POWERWHEEL", "" + degree);
mSweep = degree;
If you are still experiencing problems check that mSweep is always in the range 0 to 360 degrees.
I have a dial that I display wind direction in and the arrow displays well in some positions, but others its edges are pixelated. Here is the code to render the image:
public class DialView extends View {
private Context mContext;
private Bitmap mArrow;
private WeatherDataModel mWdm;
private float iters = 10.0f;
private static float previousAngle = 0.0f;
private int mHourIndex = 0;
private boolean isHourly = false;
private final int XLARGE = 0x4;
public DialView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
int screenLayout = mContext.getApplicationContext().getResources().getConfiguration().screenLayout;
mArrow = Utilities.applyFilter(context, BitmapFactory.decodeResource(context.getResources(), R.drawable.wind_arrow));
}
#Override
public void onDraw(Canvas canvas) {
float degrees = 0.0f;
degrees = (!isHourly) ? cardinalToDegrees(mWdm) : cardinalToDegrees(mWdm.hourly.get(mHourIndex));
Bitmap bit;
int originY = getHeight() / 2;
int originX = getWidth() / 2;
int r = originY > originX ? getWidth() * 8 / 27 : getHeight() * 8 / 27;
int x, y;
Matrix matrix = new Matrix();
degrees = (previousAngle * (iters / 10.0f) + degrees * (10.0f - iters) / 10.0f);
//Log.d(DEBUG_TAG, "Previous angle = " + previousAngle + " degrees" + degrees);
matrix.postRotate(degrees - 90.f);
bit = Bitmap.createBitmap(mArrow, 0, 0, mArrow.getWidth(), mArrow.getHeight(), matrix, false);
x = (int)(Math.cos(Math.PI * degrees / 180.0f) * r) + originX - (bit.getWidth() / 2);
y = (int)(Math.sin(Math.PI * degrees / 180.0f) * r) + originY - (bit.getHeight() / 2);
//Log.d(DEBUG_TAG, "x: " + x + " y: " + y);
canvas.drawBitmap(bit, x, y, null);
if (iters > 0) {
invalidate();
iters--;
}
previousAngle = degrees;
}
Here is the arrow good:
Here it is pixelated:
Any ideas how to handle this?
try to define a paint object and enable AntiAlias
like this:
mPaint.setAntiAlias(true);
canvas.drawBitmap(bit, x, y, mPaint);
i was draw a pie chart using canvas in android and using the below code i draw a text on each slice of that pie chart (draw arc on path), now i want to draw the text length wise i.e. from center to end of the each slice,so how to rotate the arc using start and sweep angle.
p.addArc(mEventsRect, fStartAngle, fSweepAngle);
mBgPaints.setColor(iTextColor);
canvas.drawTextOnPath(sTextValue, p, fHOffSet, fVOffSet, mBgPaints);
You can try this snippet: (from: http://www.helloandroid.com/tutorials/how-use-canvas-your-android-apps-part-2)
int x = 75;
int y = 185;
paint.setColor(Color.GRAY);
paint.setTextSize(25);
String rotatedtext = "Rotated helloandroid :)";
//Draw bounding rect before rotating text:
Rect rect = new Rect();
paint.getTextBounds(rotatedtext, 0, rotatedtext.length(), rect);
canvas.translate(x, y);
paint.setStyle(Paint.Style.FILL);
canvas.drawText(rotatedtext , 0, 0, paint);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(rect, paint);
canvas.translate(-x, -y);
paint.setColor(Color.RED);
canvas.rotate(-45, x + rect.exactCenterX(),y + rect.exactCenterY());
paint.setStyle(Paint.Style.FILL);
canvas.drawText(rotatedtext, x, y, paint);
A bit late to the party but I had to figure this one out and it's a bit simpler than what I found around. You'll already have the x and y for your text, use these to rotate the canvas
canvas.rotate(yourDegrees, x, y)
canvas.drawText(yourText, x, y, yourPaint)
canvas.rotate(-yourDegrees, x, y)
The negative sign negates the first rotation. You could swap it around to rotate in the opposite direction.
You could do this in a loop but the rotation cycle must be done each time either coordinate changes.
may be this will help you,,
here 39.5 is radius,, this will perfectly show result on mdpi screen
protected void onDraw(){
canvas.save();
PointF pf = PointOnCircle(35f, 45f, new PointF(39.5f, 39.5f));
canvas.rotate(-45, pf.x, pf.y);
canvas.drawText("67%", pf.x, pf.y, red);//23.5
canvas.restore();
canvas.save();
PointF pfa = PointOnCircle(35f, 135f, new PointF(39.5f, 39.5f));
canvas.rotate(45, pfa.x, pfa.y);
canvas.drawText("33%", pfa.x, pfa.y, red);//23.5
canvas.restore();
canvas.save();
pfa = PointOnCircle(27.5f, 225f, new PointF(39.5f, 39.5f));
canvas.rotate(-45, pfa.x, pfa.y);
canvas.drawText("45%", pfa.x, pfa.y, red);//23.5
canvas.restore();
canvas.save();
pfa = PointOnCircle(27.5f, 315f, new PointF(39.5f, 39.5f));
canvas.rotate(45, pfa.x, pfa.y);
canvas.drawText("55%", pfa.x, pfa.y, red);//23.5
canvas.restore();}
protected static final PointF PointOnCircle(float radius, float angleInDegrees, PointF origin) {
// Convert from degrees to radians via multiplication by PI/180
float x = (float) (radius * Math.cos(angleInDegrees * Math.PI / 180F)) + origin.x;
float y = (float) (radius * Math.sin(angleInDegrees * Math.PI / 180F)) + origin.y;
return new PointF(x, y);
}
Here's how i finally did it after two days of search with help of this library https://github.com/Ken-Yang/AndroidPieChart
And equations to center text done with help of my friends and alot of search
on MainActivity onCreate or oncreateView if you are using fragments:
PieChart pie = (PieChart) rootView.findViewById(R.id.pieChart);
ArrayList<Float> alPercentage = new ArrayList<Float>();
alPercentage.add(2.0f);
alPercentage.add(8.0f);
alPercentage.add(20.0f);
alPercentage.add(10.0f);
alPercentage.add(10.0f);
alPercentage.add(10.0f);
alPercentage.add(10.0f);
alPercentage.add(10.0f);
alPercentage.add(10.85f);
alPercentage.add(9.15f);
try {
// setting data
pie.setAdapter(alPercentage);
// setting a listener
pie.setOnSelectedListener(new OnSelectedLisenter() {
#Override
public void onSelected(int iSelectedIndex) {
Toast.makeText(getActivity(),
"Select index:" + iSelectedIndex,
Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
if (e.getMessage().equals(PieChart.ERROR_NOT_EQUAL_TO_100)) {
Log.e("kenyang", "percentage is not equal to 100");
}
}
public class PieChart extends View {
public interface OnSelectedLisenter {
public abstract void onSelected(int iSelectedIndex);
}
private OnSelectedLisenter onSelectedListener = null;
private static final String TAG = PieChart.class.getName();
public static final String ERROR_NOT_EQUAL_TO_100 = "NOT_EQUAL_TO_100";
private static final int DEGREE_360 = 360;
private static String[] PIE_COLORS = null;
private static int iColorListSize = 0;
ArrayList<Float> array;
private Paint paintPieFill;
private Paint paintPieBorder;
private Paint paintCenterCircle;
private ArrayList<Float> alPercentage = new ArrayList<Float>();
private int mCenterX = 320;
private int mCenterY = 320;
private int iDisplayWidth, iDisplayHeight;
private int iSelectedIndex = -1;
private int iCenterWidth = 0;
private int iShift = 0;
private int iMargin = 0; // margin to left and right, used for get Radius
private int iDataSize = 0;
private Canvas canvas1;
private RectF r = null;
private RectF centerCircle = null;
private float fDensity = 0.0f;
private float fStartAngle = 0.0f;
private float fEndAngle = 0.0f;
float fX;
float fY;
public PieChart(Context context, AttributeSet attrs) {
super(context, attrs);
PIE_COLORS = getResources().getStringArray(R.array.colors);
iColorListSize = PIE_COLORS.length;
array = new ArrayList<Float>();
fnGetDisplayMetrics(context);
iShift = (int) fnGetRealPxFromDp(30);
iMargin = (int) fnGetRealPxFromDp(40);
centerCircle = new RectF(200, 200, 440, 440);
// used for paint circle
paintPieFill = new Paint(Paint.ANTI_ALIAS_FLAG);
paintPieFill.setStyle(Paint.Style.FILL);
// used for paint centerCircle
paintCenterCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
paintCenterCircle.setStyle(Paint.Style.FILL);
paintCenterCircle.setColor(Color.WHITE);
// used for paint border
paintPieBorder = new Paint(Paint.ANTI_ALIAS_FLAG);
paintPieBorder.setStyle(Paint.Style.STROKE);
paintPieBorder.setStrokeWidth(fnGetRealPxFromDp(3));
paintPieBorder.setColor(Color.WHITE);
Log.i(TAG, "PieChart init");
}
// set listener
public void setOnSelectedListener(OnSelectedLisenter listener) {
this.onSelectedListener = listener;
}
float temp = 0;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.i(TAG, "onDraw");
float centerX = (r.left + r.right) / 2;
float centerY = (r.top + r.bottom) / 2;
float radius1 = (r.right - r.left) / 2;
radius1 *= 0.5;
float startX = mCenterX;
float startY = mCenterY;
float radius = mCenterX;
float medianAngle = 0;
Path path = new Path();
for (int i = 0; i < iDataSize; i++) {
// check whether the data size larger than color list size
if (i >= iColorListSize) {
paintPieFill.setColor(Color.parseColor(PIE_COLORS[i
% iColorListSize]));
} else {
paintPieFill.setColor(Color.parseColor(PIE_COLORS[i]));
}
fEndAngle = alPercentage.get(i);
// convert percentage to angle
fEndAngle = fEndAngle / 100 * DEGREE_360;
// if the part of pie was selected then change the coordinate
if (iSelectedIndex == i) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
float fAngle = fStartAngle + fEndAngle / 2;
double dxRadius = Math.toRadians((fAngle + DEGREE_360)
% DEGREE_360);
fY = (float) Math.sin(dxRadius);
fX = (float) Math.cos(dxRadius);
canvas.translate(fX * iShift, fY * iShift);
}
canvas.drawArc(r, fStartAngle, fEndAngle, true, paintPieFill);
float angle = (float) ((fStartAngle + fEndAngle / 2) * Math.PI / 180);
float stopX = (float) (startX + (radius/2) * Math.cos(angle));
float stopY = (float) (startY + (radius/2) * Math.sin(angle));
// if the part of pie was selected then draw a border
if (iSelectedIndex == i) {
canvas.drawArc(r, fStartAngle, fEndAngle, true, paintPieBorder);
canvas.drawLine(startX, startY, stopX, stopY, paintPieFill);
canvas.restore();
}
fStartAngle = fStartAngle + fEndAngle;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// get screen size
iDisplayWidth = MeasureSpec.getSize(widthMeasureSpec);
iDisplayHeight = MeasureSpec.getSize(heightMeasureSpec);
if (iDisplayWidth > iDisplayHeight) {
iDisplayWidth = iDisplayHeight;
}
/*
* determine the rectangle size
*/
iCenterWidth = iDisplayWidth / 2;
int iR = iCenterWidth - iMargin;
if (r == null) {
r = new RectF(iCenterWidth - iR, // top
iCenterWidth - iR, // left
iCenterWidth + iR, // right
iCenterWidth + iR); // bottom
}
if (centerCircle == null) {
// centerCircle=new RectF(left, top, right, bottom);
}
setMeasuredDimension(iDisplayWidth, iDisplayWidth);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// get degree of the touch point
double dx = Math.atan2(event.getY() - iCenterWidth, event.getX()
- iCenterWidth);
float fDegree = (float) (dx / (2 * Math.PI) * DEGREE_360);
fDegree = (fDegree + DEGREE_360) % DEGREE_360;
// get the percent of the selected degree
float fSelectedPercent = fDegree * 100 / DEGREE_360;
// check which pie was selected
float fTotalPercent = 0;
for (int i = 0; i < iDataSize; i++) {
fTotalPercent += alPercentage.get(i);
if (fTotalPercent > fSelectedPercent) {
iSelectedIndex = i;
break;
}
}
if (onSelectedListener != null) {
onSelectedListener.onSelected(iSelectedIndex);
}
invalidate();
return super.onTouchEvent(event);
}
private void fnGetDisplayMetrics(Context cxt) {
final DisplayMetrics dm = cxt.getResources().getDisplayMetrics();
fDensity = dm.density;
}
private float fnGetRealPxFromDp(float fDp) {
return (fDensity != 1.0f) ? fDensity * fDp : fDp;
}
public void setAdapter(ArrayList<Float> alPercentage) throws Exception {
this.alPercentage = alPercentage;
iDataSize = alPercentage.size();
float fSum = 0;
for (int i = 0; i < iDataSize; i++) {
fSum += alPercentage.get(i);
}
if (fSum != 100) {
Log.e(TAG, ERROR_NOT_EQUAL_TO_100);
iDataSize = 0;
throw new Exception(ERROR_NOT_EQUAL_TO_100);
}
}
in your Layout:
<com.example.piecharts.PieChart
android:id="#+id/pieChart"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</com.example.piecharts.PieChart>
This question is pretty old, but I figured I would write a general answer.Here I assume you want to draw your pie chart in the middle of the canvas and that you have your start and seep angles in an array.
x = canvas.getWidth/2 //Horizontal center of canvas view
y = canvas.getHeight/2 //Vertical center of canvas view
canvas.rotate(fStartAngle[i]+ fSweepAngle[i]/2, x ,y ); //Rotates canvas to a line in the middle
//of start and end of arc
canvas.translate(50f,0);//Moves the text a little out of the center of the circle (50f is arbitrary)
paintText.setStyle(Paint.Style.FILL);
canvas.drawText(rotatedtext, x, y, paintText);
//Undo the translations and rotations so that next arc can be drawn normally
canvas.translate(-50f,0);
canvas.rotate(-(temp+ value_degree[i]/2), x ,y );
it's 2023 there might be other answers out there but here is one that is sure to work
//the path where your text/paint will be drawn across
Path path = new Path();
path.addArc(mEventsRect, fStartAngle, fSweepAngle);//add this if you want your path to be drawn across the arc of your sector
//if you are using a text get the width
float textWidth = mTextPaint.measureText("text");
//this is the y co-ordinate your text will start from
int hOffset = 100;
//this is the x co-ordinate your text will start from
int vOffset = 100;
//we will be using the matrix to rotate the bunds of our current path
Matrix matrix = new Matrix();
//we will use this to get the bounds of our current path
RectF bounds = new RectF();
path.computeBounds(bounds,true);
//we are using the matrix to rotate the bound (with is the bound of the path) by 90 degrees
matrix.setRotate(90,bounds.centerX(),bounds.centerY());
the we transform the points in the path using the matrix
path.transform(matrix);
//you can now draw the text on the path
canvas.drawTextOnPath("text", path, hOffset, vOffset , mBgPaints);