I'm doing a simple drum set app where the users can click the button to make the corresponding sound and draw a circle on the canvas at a random location. For the canvas, I created a custom view called CanvasView, then I implements that CanvasView into the MainActivity, so I can control that View each time the buttons are clicked with OnClickListener in the MainActivity.
However, I don't know how to actually control (draw a circle on) the CanvasView using the OnClickListener. I need help on this part
This is my code for the MainActivity class:
public class MainActivity extends Activity {
//setup variables for soundpool
.
.
.
//implements CanvasView
CanvasView mCanvasView;
//set up soundID for each sound
.
.
.
//setup buttons
Button mKick;
.
.
.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//set up soundpools
.
.
.
//example, the kick drum button
//kick drum
mKick = (Button) findViewById(R.id.kick);
mKick.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
soundPool.play(kick, leftVolume, rightVolume, priority, no_loop, normal_playback_rate);
// mCanvasView.draw(CanvasView.mCanvas);
}
});
This is my code for the CanvasView
public class CanvasView extends View {
public Paint mPaint;
public static Canvas mCanvas;
//constructor
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
}
//what I want to draw is here
protected void onDraw(Canvas canvas) {
mCanvas = canvas;
super.onDraw(mCanvas);
canvas.drawColor(Color.GRAY);
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Style.STROKE);
mPaint.setAntiAlias(true);
canvas.drawCircle(30, 30, radius, mPaint);
This is my layout XML for the MainActivity
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/GridLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:columnCount="3"
android:orientation="horizontal"
android:rowCount="5"
tools:context=".GridXMLActivity" >
<Button
android:id="#+id/kick"
android:layout_width="78dp"
android:layout_height="wrap_content"
android:layout_column="1"
android:layout_gravity="center_horizontal|fill_vertical"
android:layout_row="3"
android:text="Kick" />
<com.example.virtualdrumset.CanvasView
android:id="#+id/canvasView1"
android:layout_width="143dp"
android:layout_height="169dp"
android:layout_column="1"
android:layout_gravity="left|top"
android:layout_row="0" />
I deeply apologize for any inconvenience or mistakes. This is my first time asking question.
You shouldn't call onDraw function of the canvas directly from the activity. Instead make a public method in the canvas view and write your logic there and call invalidate at the end. This calls onDraw method and contents are drawn on the screen again according to your new logic.
If you want a circle to be drawn at random locations on screen each time button is clicked you can do something like this
public class CanvasView extends View {
public Paint mPaint;
public static Canvas mCanvas;
private int mPivotX = 0;
private int mPivotY = 0;
private int radius = 60;
//constructor
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
}
public void drawCircle() {
int minX = radius * 2;
int maxX = getWidth() - (radius *2 );
int minY = radius * 2;
int maxY = getHeight() - (radius *2 );
//Generate random numbers for x and y locations of the circle on screen
Random random = new Random();
mPivotX = random.nextInt(maxX - minX + 1) + minX;
mPivotY = random.nextInt(maxY - minY + 1) + minY;
//important. Refreshes the view by calling onDraw function
invalidate();
}
//what I want to draw is here
protected void onDraw(Canvas canvas) {
mCanvas = canvas;
super.onDraw(mCanvas);
canvas.drawColor(Color.GRAY);
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Style.STROKE);
mPaint.setAntiAlias(true);
canvas.drawCircle(mPivotX, mPivotY, radius, mPaint);
}
}
And then onButtonClick
mKick.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
soundPool.play(kick, leftVolume, rightVolume, priority, no_loop, normal_playback_rate);
mCanvasView.drawCircle()
}
Hope it helps!
Related
I have a custom view that is a circle. Here is the code for my CircleView:
public class CircleView extends View {
private static final int START_ANGLE_POINT = 90;
private final Paint paint;
private final RectF rect;
private float angle;
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
final int strokeWidth = 40;
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(strokeWidth);
//Circle color
paint.setColor(Color.RED);
rect = new RectF(strokeWidth, strokeWidth, 1000 + strokeWidth, 1000 + strokeWidth);
//Initial angle is zero
angle = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint);
}
public float getAngle() {
return angle;
}
public void setAngle(float angle) {
this.angle = angle;
} }
and here is how I declare it in the xml layout of an activity:
<com.my_package.ui.recording.CircleView
android:id="#+id/circleView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
All standard stuff. This is how my custom image looks like
Now, I want to place an imageView in the centre on the circleView? Does any one know how can I achieve that?
This is ideally what I would like to end up with:
Thank you in advance.
If you aren't set on using an ImageView and really just want to draw the bitmap in the center then have a look at canvas' drawBitmap method. This will allow you to draw it however/wherever you want.
My task is Drawing a Circle Diagram.
I have 4 arcs.
On each arc, I have 2 values to make View Animate.
this image
will show you more detail.
Can Anyone Suggest me the Animation should I use for each value?
And how can I make it Animate by Specific Angle?
Edit: I upload .gif file for more detail.
You can make a custom View and a custom animation. Override the applyTransformation() Method in the custom Animation to apply the transformation.
public class ArcView extends View {
private final Paint mPaint;
private final RectF mRect;
private float arcAngle;
public ArcView(Context context, AttributeSet attrs) {
super(context, attrs);
// Set Angle to 0 initially or whatever you want
arcAngle = 0;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(4);
mPaint.setColor(Color.WHITE);
mRect = new RectF(2, 2, 78, 78);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(mRect, 90, arcAngle, false, mPaint);
}
public float getArcAngle() {
return arcAngle;
}
public void setArcAngle(float arcAngle) {
this.arcAngle = arcAngle;
}
}
And here is how your animation Class looks like
public class ArcAngleAnimation extends Animation {
private ArcView arcView;
private float oldAngle;
private float newAngle;
public ArcAngleAnimation(ArcView arcView, int newAngle) {
this.oldAngle = arcView.getArcAngle();
this.newAngle = newAngle;
this.arcView = arcView;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation transformation) {
float angle = oldAngle + ((newAngle - oldAngle) * interpolatedTime);
arcView.setArcAngle(angle);
arcView.requestLayout();
}
public void setNewAngle(int newAngle){
this.newAngle = newAngle;
}
public void setOldAngle(float oldAngle) {
this.oldAngle = oldAngle;
}
}
Now all you need to do is apply animation and run it in your activity or fragment
ArcView view = (ArcView) findViewById(R.id.arc_view);
ArcAngleAnimation arcAnimation;
arcAnimation = new ArcAngleAnimation(view, 30);
arcAnimation.setFillAfter(true);
arcAnimation.setDuration(200);
view.startAnimation(arcAnimation);
fixed size circle aniamtion problem
hello there , i have this class :
public circle (Context context, AttributeSet attrs) {
super(context, attrs);
final int strokeWidth = 30;
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(strokeWidth);
//Circle color
paint.setColor(Color.YELLOW);
//size 200x200 example
rect = new RectF(strokeWidth, strokeWidth, 350 + strokeWidth, 350 +
strokeWidth);
//Initial Angle (optional, it can be zero)
angle = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(rect, START_ANGLE_POINT, angle, false, paint);
}
public float getAngle() {
return angle;
}
public void setAngle(float angle) {
this.angle = angle;
}
}
and this class is responsible for animation draw circle
the animation class is :
public class CircleAngleAnimation extends Animation {
private circle circle;
private float oldAngle;
private float newAngle;
public CircleAngleAnimation(circle circle, int newAngle) {
this.oldAngle = circle.getAngle();
this.newAngle = newAngle;
this.circle = circle;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation
transformation) {
float angle = oldAngle + ((newAngle - oldAngle) * interpolatedTime);
circle.setAngle(angle);
circle.requestLayout();
}
}
i attached xml value in my mainactivity.xml to the circle class like this :
<com.mynetwork.zaidkhaled.speech.circle
android:id="#+id/circle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
/>
in mainactivity i set animation = new CircleAngleAnimation(circle, 360); animation.setDuration(1000); then i call start animation by circle.startanimation(animation);
now my problem is when this circle is drawn in the activity , if the screen resolution is high it will be drawn perfectly , perfect sized , if the screen resolution is low it will be drawn very very big , how can set this cricle to be drawn in the same size on every mobile device ?
thanks for help :)
I'm new to Android development.
I have a class DrawView that extends View, it's like a simple paint app
public class DrawView extends View implements OnTouchListener {
Bitmap bitmap;
Canvas bitmapCanvas;
int color;
// Position of finger down
float pX, pY;
// Position of finger up
float mX, mY;
// Create new path
Path path = new Path();
// Is view initialized?!
boolean isInitialized;
// Create new paint
Paint paint = new Paint();
int begX, begY, endX, endY = 0;
//DrawView constructor
public DrawView(Context context) {
// Initialize new view
super(context);
setFocusable(false);
setFocusableInTouchMode(false);
this.setOnTouchListener(this);
requestLayout();
paint.setAntiAlias(true);
paint.setStyle(Style.STROKE);
// There is no bitmap yet
isInitialized = false;
}
//Initialize bitmap and canvas
private void init() {
bitmap = Bitmap.createBitmap(getWidth(), getHeight()/2, Bitmap.Config.RGB_565);
bitmap.setPixel(72, 72, Color.BLACK);
// Create new canvas and set bitmap
bitmapCanvas = new Canvas();
bitmapCanvas.setBitmap(bitmap);
// ... set canvas background color
bitmapCanvas.drawColor(Color.WHITE);
// We're done with initialization
isInitialized = true;
}
//Reset canvas
public void reset(){
bitmapCanvas.drawColor(Color.WHITE);
}
//Handle event 'onDraw'
#Override
public void onDraw(Canvas canvas) {
// Check if initialized
if (!isInitialized)
init();
// Draw bitmap!
canvas.drawBitmap(bitmap, 0, 0, paint);
}
//Handle event 'onTouch'
public boolean onTouch(View view, MotionEvent event) {
// Check event type
switch (event.getAction()) {
// Finger down
case MotionEvent.ACTION_DOWN:
paint.setColor(Color.BLACK);
paint.setStrokeWidth(7f);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setAntiAlias(true);
// Get current position
pX = event.getX();
pY = event.getY();
// Set beginning of path to (posX,posY)
path.moveTo(pX, pY);
begX= (int) pX;
begY = (int) pY;
bitmapCanvas.drawPoint(pX, pY, paint);
break;
// Finger moves
case MotionEvent.ACTION_MOVE:
mX = event.getX();
mY = event.getY();
// Set position of end of path
path.lineTo(mX, mY);
endX = (int) mX;
endY = (int) mY;
// Draw path
bitmapCanvas.drawPath(path, paint);
// Invalidate canvas (redraw the view)
invalidate();
break;
// Finger up
case MotionEvent.ACTION_UP:
mX = event.getX();
mY = event.getY();
if (mY == pY && mX == pX){
bitmapCanvas.drawPoint(pX, pY, paint);
invalidate();
}
path.reset();
break;
}
return true;
}
}
In my default layout, I want it to contains DrawView and other elements (button, textview ...)
How can I split "default layout" to contains DrawView with these elements?
Thanks
edit:
Where should I put this code to make DrawView work correctly
public class Draw extends Activity {
DrawView drawView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawView = new DrawView(this);
setContentView(drawView);
drawView.requestFocus();
}
}
Add your view with it's full name to your layout.For example:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
...>
<TextView.../>
<my.package.MyCustomView
android:id="#+id/my_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<Button.../>
</LinearLayout>
Here MyCustomView is name of java class that extends View and my.package is name of package that contains that class.You can see that you can add LayoutParams to it,as I added layout_height or layout_width.
Edit:
If you want to use your custom view in XML layout,you have to add at least this constructor to your class:
public MyCustomView(Context context, AttributeSet attrs){
super(context, attrs);
...
}
I don't know how you want actually but you can use any layout as per your requirement here is the simple layout which your your view and another views in split screen
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_weight="1">
<TextView /> <!--your textview-->
<TextView /> <!--your textview-->
<TextView /> <!--your textview-->
</LinearLayout>
<com.androidapp.DrawView android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
This will split the screen in equal size for your view and another view with nested LinearLayout
If you want to display your content with wrap size then just remove the weight if you display at top of your DrawView and use wrap_content in height or if you display at bottom than give them weight in 0.2 or o.3 whatever but in float
Edit
Define both constructor
public DrawView(Context context) {
// Initialize new view
super(context);
initObject();
}
public MyCustomView(Context context, AttributeSet attrs){
super(context, attrs);
initObject();
}
private void initObject(){
setFocusable(false);
setFocusableInTouchMode(false);
this.setOnTouchListener(this);
requestLayout();
paint.setAntiAlias(true);
paint.setStyle(Style.STROKE);
// There is no bitmap yet
isInitialized = false;
}
I am trying to redraw the custom view in onCreate() method
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
circleView = (CircleView)findViewById(R.id.circleView);
circleView.setCircle(100, 100, 25);
circleView.wrapView();
}
and custom view is :
public class CircleView extends View
{
private Paint paint = null;
private int x = 50;
private int y = 50;
private int radius = 50;
public CircleView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public CircleView(Context context)
{
super(context);
init();
}
private void init()
{
paint = new Paint();
}
public void setCircle(int x, int y, int radius)
{
this.x = x;
this.y = y;
this.radius = radius;
init();
this.invalidate();
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
paint.setColor(Color.WHITE);
canvas.drawCircle(x, y, radius, paint);
Log.e("", "radius : " + radius);
}
public void setColor(int color)
{
paint.setColor(color);
}
public void wrapView()
{
this.setLayoutParams(new RelativeLayout.LayoutParams(radius*2, radius*2));
this.invalidate();
}
}
and xml is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/layoutMain"
>
<com.pep1439.view.CircleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/circleView" />
</RelativeLayout>
i just want to resize the circle, but failed. Help me to draw circle with any radius. How to do this. Its working fine if i use default values. It draws the circle when i remove the line circleView.setCircle(100, 100, 25);. I want to adjust circle at run time.
thanks.
You set x and y to 100 and radius to 25. Then you resize your view to radius*2, which is 50, so in the end you're drawing a circle of radius 25 at position 100,100 on a view that is only 50x50 in size. In other words: You draw your circle outside the area of your view.