I have following TextView
public class Cube extends TextView {
Context mContext;
Drawable background;//Hintergrund des Blocks
char mLetter;//Buchstabe des Blocks
int x, y;//Koordinaten des Blocks
#SuppressWarnings("deprecation")
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public Cube(Context context, char letter, int _x, int _y) {
super(context);
mContext = context;
mLetter = letter;
background = ContextCompat.getDrawable(getContext(), R.drawable.cube);
x = _x;
y = _y;
this.setText("" + letter);
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
this.setBackgroundDrawable(background);
else
this.setBackground(background);
}
public void drawCube(Canvas canvas){//how to draw now!? This is called from a separate thread in SurfaceView
}
}
If I call following in drawCube():
background.setBounds(x, y, x + 20, y + 20);
background.draw(canvas);
it just draws the backgroundDrawable. But how can I draw it with the text/the letter inside? That it looks like this: (The background ist the canvas, the orange and white one is the Background and the "A" is the letter/text)
EDIT: Code at 21.09
This is my (shortened) thread:
public class CanvasThread extends Thread {
private SurfaceHolder mSh;
private ArrayList<Cube> mCubes;
private Canvas mCanvas;
private Context mContext;
private boolean mRun = false;
private boolean mDown = false;
private boolean newCube = false;
public CanvasThread(SurfaceHolder sh, Context context){
mSh = sh;
mCubes = new ArrayList<>();
mContext = context;
}
public void run(){
while(mRun){
mCanvas = null;
try{
mCanvas = mSh.lockCanvas(null);
synchronized (mSh){
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
newCube = true;
for(int i = 0; i < mCubes.size(); i++){
if(mCubes.get(i).getSpeed() > 0)
newCube = false;
if(mDown) {
if (mCubes.get(i).moveDown(feld)) {
mDown = false;
}
}
//mCubes.get(i).invalidate();
//mCubes.get(i).requestLayout();
mCubes.get(i).draw(mCanvas);
}
if(newCube)
addCube();
}
} finally {
if(mCanvas != null){
mSh.unlockCanvasAndPost(mCanvas);
}
}
}
}
public void addCube(){
Random r = new Random();
Cube cube = new Cube(mContext, mBuchstaben[r.nextInt(29)], r.nextInt(10), 0, mCanvas);
mCubes.add(cube);
}
}
This is my (shortened) fragment which uses the canvas/surface view:
public class KlassischFragment extends Fragment implements SurfaceHolder.Callback {
SurfaceHolder sh;
SurfaceView sv;
private CanvasThread thread;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_klassisch, container, false);
sv = (SurfaceView) view.findViewById(R.id.surfaceView);
sh = sv.getHolder();
sh.addCallback(this);
sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
return view;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new CanvasThread(sh, getContext());
thread.setRunnable(true);
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
//thread.setRunnable(false);
while(retry){
try{
thread.join();
retry = false;
} catch(InterruptedException ie){
//Immer wieder versuchen
}
break;
}
thread = null;
}
}
Here is an example on how to draw a text on top of a square. Some of the values hardcoded but you should be able to make them dynamic.
public class Cube extends View {
private final static String TEST_STRING = "ABC";
private Paint mBackgroundPaint;
private Paint mTextPaint;
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public Cube(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public Cube(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public Cube(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public Cube(Context context) {
this(context, null, -1);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Just for demo purposes this should be calculated properly
int desiredWidth = 100;
int desiredHeight = 100;
setMeasuredDimension(desiredWidth, desiredHeight);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int savedCount = canvas.save();
drawRectangle(canvas);
drawText(canvas);
canvas.restoreToCount(savedCount);
}
private void init() {
mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBackgroundPaint.setColor(Color.BLUE);
mBackgroundPaint.setStyle(Paint.Style.FILL);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
// This need to be adjusted based on the requirements that you have
mTextPaint.setTextSize(20.0f);
}
private void drawRectangle(Canvas canvas) {
canvas.drawRect(0, 0, getWidth(), getHeight(), mBackgroundPaint);
}
private void drawText(Canvas canvas) {
Rect rect = new Rect();
// For simplicity I am using a hardcoded string
mTextPaint.getTextBounds(TEST_STRING, 0, 1, rect);
int w = getWidth(), h = getHeight();
float x = (w - rect.width()) / 2, y = ((h - rect.height()) / 2) + rect.height();
canvas.drawText(TEST_STRING, 0, 1, x, y, mTextPaint);
}
}
Related
I've followed some forums and I'm lost with this problem:
I have a Custom View that draws 9 circles for me as shown below:
This circles must be an icon to the main one and 8 images for the others and it must be a drawable resource (I have png pictures in on my drawable folder).
How may I proceed to set this drawable images instead of the colors?
This is my actual code:
public class CircleView extends View {
public static interface IMenuListener{
public void onMenuClick(MenuCircle item);
}
public static class MenuCircle{
private int x,y,radius;
public int id;
public String text;
}
private Paint mainPaint;
private Paint secondPaint;
private Paint textPaint;
private int radius_main =130;
private int menuInnerPadding = 40;
private int radialCircleRadius = 60;
private int textPadding = 25;
private double startAngle = - Math.PI/2f;
private ArrayList<MenuCircle> elements;
private IMenuListener listener;
public void setListener(IMenuListener listener){
this.listener = listener;
}
public void clear(){
elements.clear();
listener=null;
}
public CircleView(Context context) {
super(context);
init();
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
elements = new ArrayList<>();
}
public void addMenuItem(String text,int id){
MenuCircle item = new MenuCircle();
item.id = id;
item.text=text;
elements.add(item);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mainPaint = new Paint();
mainPaint.setColor(Color.DKGRAY); //color of main circle
secondPaint = new Paint();
secondPaint.setColor(Color.DKGRAY); // color of 8 circles
textPaint = new Paint();
textPaint.setColor(Color.BLACK); // text under 8 circles
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centerX = canvas.getWidth()/2 ;
int centerY= canvas.getHeight()/2;
canvas.drawCircle(centerX,centerY,radius_main,mainPaint);
for(int i=0;i<elements.size();i++){
double angle =0;
if(i==0){
angle = startAngle;
}else{
angle = startAngle+(i * ((2 * Math.PI) / elements.size()));
}
elements.get(i).x = (int) (centerX + Math.cos(angle)*(radius_main+menuInnerPadding+radialCircleRadius));
elements.get(i).y = (int) (centerY + Math.sin(angle)*(radius_main+menuInnerPadding+radialCircleRadius));
canvas.drawCircle( elements.get(i).x,elements.get(i).y,radialCircleRadius,secondPaint);
float tW = textPaint.measureText(elements.get(i).text);
canvas.drawText(elements.get(i).text,elements.get(i).x-tW/2,elements.get(i).y+radialCircleRadius+textPadding,textPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){
for(MenuCircle mc : elements){
double distance = Math.hypot(event.getX()-mc.x,event.getY()-mc.y);
if(distance<= radialCircleRadius){
//touched
if(listener!=null)
listener.onMenuClick(mc);
return true;
}
}
}
return super.onTouchEvent(event);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
}
I have created my custom View in Android and trying to draw a circle in that but nothing is drawing but with no errors.
Here is my code
public class ColorOptionsView extends RelativeLayout {
private View mValue;
private ImageView mImage;
private Paint paint;
String cirlceText;
int circleColor,circleTextColor;
float circleTextSize;
public ColorOptionsView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ColorOptionsView, 0, 0);
try {
cirlceText = a.getString(R.styleable.ColorOptionsView_circleText);
circleColor = a.getColor(R.styleable.ColorOptionsView_circleColor, 0);
circleTextColor = a.getColor(R.styleable.ColorOptionsView_circleTextColor, 0);
circleTextSize = a.getFloat(R.styleable.ColorOptionsView_circleTextSize,20);
} finally {
a.recycle();
}
}
public void setCirlceText(String cirlceText) {
this.cirlceText = cirlceText;
invalidate();
requestLayout();
}
public void setCircleColor(int circleColor) {
this.circleColor = circleColor;
invalidate();
requestLayout();
}
public void setCircleTextColor(int circleTextColor) {
this.circleTextColor = circleTextColor;
invalidate();
requestLayout();
}
public void setCircleTextSize(float circleTextSize) {
this.circleTextSize = circleTextSize;
invalidate();
requestLayout();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
paint.setColor(circleColor);
int centerX = this.getMeasuredWidth()/2;
int centerY = this.getMeasuredHeight()/2;
int raduis = 150;
canvas.drawCircle(centerX,centerY,raduis,paint);
paint.setColor(circleTextColor);
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(cirlceText,centerX,centerY,paint);
canvas.drawLine(0,100,100,0,paint);
}
I am not getting where I went wrong. Devs check it and help me out.
i want to know if i'm able to change the color of the active tab indicator (that light-blue line) to black(#4A4A4A)
Here is the photo
public class PageIndicator extends View {
int totalNoOfDots;
int activeDot;
int dotSpacing;
int horizontalSpace = 5;
Bitmap activeDotBitmap;
Bitmap normalDotBitmap;
int x = 0;
private Paint paint;
public PageIndicator(Context context) {
super(context);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
activeDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_active);
normalDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_normal);
}
public PageIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
activeDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_active);
normalDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_normal);
}
public PageIndicator(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
activeDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_active);
normalDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_normal);
}
#Override
protected void onDraw(Canvas canvas) {
drawDot(canvas);
super.onDraw(canvas);
}
private void drawDot(Canvas canvas) {
for (int i = 0; i < totalNoOfDots; i++) {
if (i == activeDot) {
canvas.drawBitmap(activeDotBitmap, x, 0, paint);
} else {
canvas.drawBitmap(normalDotBitmap, x, 0, paint);
}
x = x + activeDotBitmap.getWidth() + horizontalSpace + dotSpacing;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = totalNoOfDots * (activeDotBitmap.getWidth() + horizontalSpace + getDotSpacing());
width = resolveSize(width, widthMeasureSpec);
int height = activeDotBitmap.getHeight();
height = resolveSize(height, heightMeasureSpec);
setMeasuredDimension(width, height);
}
public void refersh() {
x = 0;
invalidate();
}
public int getTotalNoOfDots() {
return totalNoOfDots;
}
public void setTotalNoOfDots(int totalNoOfDots) {
this.totalNoOfDots = totalNoOfDots;
x = 0;
invalidate();
}
public int getActiveDot() {
return activeDot;
}
public void setActiveDot(int activeDot) {
this.activeDot = activeDot;
x = 0;
invalidate();
}
public int getDotSpacing() {
return dotSpacing;
}
public void setDotSpacing(int dotSpacing) {
this.dotSpacing = dotSpacing;
x = 0;
invalidate();
}
}
if you are using support library.
add this to your tabLayout
app:tabIndicatorColor="#4A4A4A"
the idea is, i want to make animated kanji letter (in sequence) like this project HTML5 Stroke Animation. And my problem is, when i call onDraw method my canvas just draw simultaneously. I couldn't find much info about it on the internet, so any clue would be much appreciated if you have already come across the same situation.
here is my code:
public class MainActivity extends AppCompatActivity {
private TextView txt;
private SvgPathParser svgPathParser;
private PathView pathView;
private String sPath =
"M32.49,17.39c0.14,1.08,0.24,2.44-0.12,3.77c-2.29,8.41-11.14,24.16-21.81,35.56" +
"|M25.03,42c0.59,0.61,0.76,1.97,0.76,3.23c0,10.08,0.08,28.85,0,40.77c-0.02,3.48-0.04,6.4-0.04,8.38" +
"|M55.1,14.25c0.05,0.65,0.16,1.69-0.09,2.6c-1.55,5.6-8.51,16.02-17.36,24.43" +
"|M53.88,27.02c0.94,0.18,3.7,0.29,4.62,0.18c4.47-0.52,18.49-2.45,26.44-3.62c2.43-0.36,4.03-0.45,6.45-0.17" +
"|M52.82,39.44c1.03,0.85,1.4,3.75,0.72,5.89c-3.37,10.67-6.4,19.7-11.35,30.04c-1.45,3.03-0.49,4.25,1.47,4.33c10.84,0.43,18.96,1.05,29.44,3.78c5.98,1.55,12.27,4.02,17.89,7.93" +
"|M54.69,42.07c6.68-0.95,22.21-3.14,26.69-3.43c3.45-0.22,4.43,1.81,4.14,4.54c-1.33,12.48-5.94,37.8-10.23,47.46c-2.3,5.17-4.97,4.12-7.54,1.33" +
"|M68.32,43.35c0.45,0.88,0.63,2.39,0.13,4.22c-2.32,8.56-7.53,25.28-10.01,32.34" +
"|M32.07,61.64c3.43,0.61,5.94,0.44,8.42,0.17c12.25-1.31,31.7-3.07,49-3.92c2.76-0.14,5.75-0.41,8.43,0.38";
String[] arrayPath = sPath.split("\\|");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new PathView(this));
}
private Path path(String sPath) throws ParseException {
svgPathParser = new SvgPathParser();
return svgPathParser.parsePath(sPath);
}
public class PathView extends View {
Path path;
Paint paint;
List<Path> paths;
float length;
public PathView(Context context) {
super(context);
init();
}
public PathView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PathView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void init() {
paths = new ArrayList<>();
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
path = new Path();
for (int i = 0; i < arrayPath.length; i++) {
try {
paths.add(path(arrayPath[i]));
// path = );
} catch (ParseException e) {
e.printStackTrace();
}
}
// Measure the path
for (Path path : paths) {
this.path = path;
PathMeasure measure = new PathMeasure(path, false);
length = measure.getLength();
float[] intervals = new float[]{length, length};
ObjectAnimator animator = ObjectAnimator.ofFloat(PathView.this, "phase", 1.0f, 0.0f);
animator.setDuration(2000);
animator.start();
}
}
//is called by animtor object
public void setPhase(float phase) {
Log.d("pathview", "setPhase called with:" + String.valueOf(phase));
paint.setPathEffect(createPathEffect(length, phase, 0.0f));
invalidate();//will calll onDraw
}
private PathEffect createPathEffect(float pathLength, float phase, float offset) {
return new DashPathEffect(new float[]{pathLength, pathLength},
Math.max(phase * pathLength, offset));
}
#Override
public void onDraw(Canvas c) {
super.onDraw(c);
for (Path path : paths) {
this.path = path;
c.drawPath(path, paint);
}
}
}
}
I'm making a simple rotating animation of 2 images, one on top of another (each with a different speed). I know there is already an Animation API, but I need to use this one instead.
It works well, but from time to time, the animations stop for a very short time and then continue, making it "jumpy" (stays on some frames much more than on the others).
Why does it occur? because of GC? What can I do to avoid it? I intend to do some background operations, so it might get even slower.
I know that using sleep() doesn't really mean the thread will wake up right after the given time, but this is too much and it's very noticeable .
Are there any tricks to make it smoother? maybe use a better alternative?
Here's the code (of the view that does it) :
public class AnimView extends SurfaceView implements SurfaceHolder.Callback
{
int _angle;
private final Bitmap _bitmap;
private final Paint _paint =new Paint();
private AnimationThread _animationThread;
private Matrix _matrix;
private int _width;
private int _height;
public AnimView(final Context context)
{
super(context);
_bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
public AnimView(final Context context,final AttributeSet attrs)
{
super(context,attrs);
_bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
public AnimView(final Context context,final AttributeSet attrs,final int defStyle)
{
super(context,attrs,defStyle);
_bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
#Override
public void surfaceChanged(final SurfaceHolder holder,final int format,final int width,final int height)
{
_width=width;
_height=height;
}
#Override
public void surfaceCreated(final SurfaceHolder holder)
{
if(isInEditMode())
return;
_matrix=new Matrix();
setWillNotDraw(false);
_animationThread=new AnimationThread();
_animationThread.start();
}
#Override
public void surfaceDestroyed(final SurfaceHolder holder)
{
_animationThread.cancelAnimation();
}
#Override
protected void onDraw(final Canvas canvas)
{
if(isInEditMode())
{
canvas.drawColor(0xffff0000);
return;
}
_paint.setAntiAlias(true);
_matrix.reset();
_matrix.postScale(_width/_bitmap.getWidth(),_height/_bitmap.getHeight());
_matrix.postRotate(_angle,_width/2,_height/2);
canvas.drawBitmap(_bitmap,_matrix,_paint);
_matrix.reset();
_matrix.postScale(_width/_bitmap.getWidth(),_height/_bitmap.getHeight());
_matrix.postRotate(_angle*2,_width/2,_height/2);
canvas.drawBitmap(_bitmap,_matrix,_paint);
}
private class AnimationThread extends Thread
{
private boolean _isRunning =true;
public AnimationThread()
{}
public void cancelAnimation()
{
_isRunning=false;
}
#Override
public void run()
{
while(_isRunning)
{
postInvalidate();
refreshDrawableState();
try
{
sleep(5);
}
catch(final InterruptedException e)
{
e.printStackTrace();
}
_angle=(_angle+1)%360;
}
}
}
}
Try something like this
#Override
public void run()
{
long last = System.currentTimeMillis();
long currentTime = last;
long frameTime = 40;
while(_isRunning)
{
currentTime = System.currentTimeMillis();
if(currentTime - last > frameTime){
postInvalidate();
refreshDrawableState();
//I FORGOT THIS
last = currentTime;
}
try
{
sleep(5);
}
catch(final InterruptedException e)
{
e.printStackTrace();
}
_angle=(_angle+1)%360;
}
}
}
This way you refresh your screen every 40ms and update your position every 5ms. Also this is just one part, you can set your matrix update and calculations also out of the drawing part, and this will increase your speed too. The less calculations you do on actuall draw time the faster it will be.
EDIT: Take a look at this
public class AnimView extends SurfaceView implements SurfaceHolder.Callback {
int _angle;
private final Bitmap _bitmap;
private final Paint _paint = new Paint();
private AnimationThread _animationThread;
private Matrix _matrix;
private int _width = 100;
private int _height = 100;
private Bitmap backBitmap;
private Canvas backCanvas;
public AnimView(final Context context) {
super(context);
_bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
public AnimView(final Context context, final AttributeSet attrs) {
super(context, attrs);
_bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
public AnimView(final Context context, final AttributeSet attrs,
final int defStyle) {
super(context, attrs, defStyle);
_bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
_paint.setAntiAlias(true);
getHolder().addCallback(this);
}
#Override
public void surfaceChanged(final SurfaceHolder holder, final int format,
final int width, final int height) {
_width = width;
_height = height;
createImage();
}
#Override
public void surfaceCreated(final SurfaceHolder holder) {
if (isInEditMode())
return;
_matrix = new Matrix();
setWillNotDraw(false);
_animationThread = new AnimationThread();
_animationThread.start();
}
#Override
public void surfaceDestroyed(final SurfaceHolder holder) {
_animationThread.cancelAnimation();
}
#Override
protected void onDraw(final Canvas canvas) {
if (isInEditMode() || backBitmap == null) {
canvas.drawColor(0xffff0000);
return;
}
canvas.drawBitmap(backBitmap, 0, 0, _paint);
}
private class AnimationThread extends Thread {
private boolean _isRunning = true;
public AnimationThread() {
}
public void cancelAnimation() {
_isRunning = false;
}
#Override
public void run() {
long last = System.currentTimeMillis();
long currentTime = last;
long frameTime = 40;
long updateTime = 20;
boolean updated = false;
while (_isRunning) {
currentTime = System.currentTimeMillis();
if (currentTime - last > frameTime) {
postInvalidate();
refreshDrawableState();
last = currentTime;
updated = false;
}
else if(currentTime - last > updateTime){
if(!updated){
drawImage();
updated = true;
}
}
try {
sleep(5);
} catch (final InterruptedException e) {
e.printStackTrace();
}
_angle = (_angle + 1) % 360;
}
}
}
private void createImage(){
backBitmap = Bitmap.createBitmap(_width, _height, Config.ARGB_8888);
backCanvas = new Canvas();
backCanvas.setBitmap(backBitmap);
}
private void drawImage(){
backCanvas.drawRGB(0, 0, 0);
_paint.setAntiAlias(true);
_matrix.reset();
_matrix.postScale(_width / _bitmap.getWidth(),
_height / _bitmap.getHeight());
_matrix.postRotate(_angle, _width / 2, _height / 2);
backCanvas.drawBitmap(_bitmap, _matrix, _paint);
_matrix.reset();
_matrix.postScale(_width / _bitmap.getWidth(),
_height / _bitmap.getHeight());
_matrix.postRotate(_angle * 2, _width / 2, _height / 2);
backCanvas.drawBitmap(_bitmap, _matrix, _paint);
}
}
Hope this helps and enjoy your work