Call a method from activity that extends View - android

I'm doing a genre of a bull's eye, but instead of use circles I'm using squares.
But the problem is:
Everything is done, the algorithm to generate the color the others squares is done.
But I implemented a button, and I made it to refresh the bull's eye.
The problem is that I can't make, need help.
This is the MainActivity, it's from here that I will detect the button click.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FrameLayout frame = (FrameLayout) findViewById(R.id.frame);
Draw draw = new Draw(this);
frame.addView(draw);
Button refresh = (Button) findViewById(R.id.refresh);
refresh.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
draw.onDraw(canvas);
frame.addView(draw);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
And this is the Draw activity, this is the one that I used to render the image.
public class Draw extends View {
public Draw(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
Paint prop = new Paint();
Random color = new Random();
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
int oriwidth = 0;
int oriheight = 0;
for (int x = 0; x < 20; x++) {
int red = color.nextInt();
int green = color.nextInt();
int blue = color.nextInt();
prop.setARGB(0, red, green, blue);
canvas.drawRect(oriwidth += 10, oriheight += 10, width -= 10,
height -= 10, prop);
}
}
}
Can someone help me? Sorry for the english.

Is there any special reason why you're adding the Draw view programmatically during onCreate?
Try defining the Draw view in the layout xml itself. That should solve any issues with defining the width / height of the view (make sure to define width & height... try hard coded dimensions at first like 100dp by 100dp)
Once you've done that, make sure to capture your "draw" view as a member of the activity:
public class MainActivity extends Activity
{
private Draw mDraw;
Then, in your onCreate:
mDraw = (Draw)findViewById(R.id.myDrawId);
Then, in your button click listener, just call invalidate:
refresh.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mDraw.invalidate();
}
});

Try to change with this portion of code:
public void onClick(View v) {
MainActivity.this.draw.onDraw(canvas);
MainActivity.this.frame.addView(draw);
}

You shouldn't call onDraw() directly. Try draw.invalidate().

Related

Error while trying to create circular reveal: IllegalStateException: cannot start this animation on a detached view

So, I'm experimenting trying to create a circular reveal on API level 21 on a TextView but I keep getting this error. At first I thought it had something to do with the lifecycle of the fragment I was attempting it but then I just tried the same thing in an activity and it still wouldn't work.
Here's the code:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window w = getWindow();
w.setFlags(
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
w.setStatusBarColor(Color.parseColor("#0277bd"));
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.text);
int a = (tv.getLeft() + tv.getRight()) / 2;
int b = (tv.getTop() + tv.getBottom()) / 2;
int radius = tv.getWidth();
Animator anim = ViewAnimationUtils.createCircularReveal(tv, a, b, 0, radius);
anim.start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return super.onCreateOptionsMenu(menu);
}
}
It's still early days so I can't really find any answers about this. Any ideas?
You're getting the error because the view you passed in hasn't been measured and laid out on the screen yet. ViewAnimationUtils.createCircularReveal needs the target view to be measured to calculate the animation. You'll also find that your variables a and b are always 0.
If you want to experiment, create the animation and start it within a button click listener. Here's an example using your code:
Button button = (Button) findViewById(R.id.your_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView tv = (TextView) findViewById(R.id.text);
int a = (tv.getLeft() + tv.getRight()) / 2;
int b = (tv.getTop() + tv.getBottom()) / 2;
int radius = tv.getWidth();
Animator anim = ViewAnimationUtils.createCircularReveal(tv, a, b, 0, radius);
anim.start();
}
});
You can use Runnable to do the animation. The Runnable will run after the view's creation. No need to post delay.
view.post(new Runnable()
{
#Override
public void run(){
//create your anim here
}
});
Or you can do this.
tv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
tv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
tv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
Animator anim = ViewAnimationUtils.createCircularReveal(tv, a, b, 0, radius);
anim.start();
}
});
Adding GlobalLayoutListener to wait for the view to be inflated worked for me.
Or you can do this.
tv.postDelayed(new Runnable() {
#Override
public void run() {
//start your animation here
}
}, 1000);

Making canvas background as XML layout

I have an XML layout. I want to draw a line after getting the button clicked. I made an inner class to accomplish it. But when it do so my content view get changed to canvas of View class.
I want my content view to be the same XML with the line I generated by clicking a Button.
Thank you.
Code:
public class Dots extends Activity implements View.OnClickListener
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dots);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
b[i][j] = (Button) findViewById(refbutton[i][j]);
b[i][j].setOnClickListener(this);
}
}
}
private static class SampleView extends View
{
public SampleView(Context context)
{
super(context);
}
protected void onDraw(Canvas canvas)
{
Paint p = new Paint();
p.setColor(Color.BLACK);
p.setStyle(Paint.Style.STROKE);
canvas.drawLine(5, 5, 25, 5, p);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
//getMenuInflater().inflate(R.menu.dots, menu);
return true;
}
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
SampleView d=new SampleView(this);
setContentView(d);
}
}

Android invalidate doesn't show intermediate animation

This is my code.
On swipe to the top is performed:
for(int it = 0;it<4;it++){
myBoard.step_up();
invalidate();
}
int ad = myBoard.merge_up();
invalidate();
for(int it = 0;it<4;it++){
myBoard.step_up();
invalidate();
}
step_up and merge_up methods change the values of myBoard. The onDraw method draws the screen according to the myBoard values. But i do not see intermediate results of movements! Just start postition and then end position, the same as in the following code:
for(int it = 0;it<4;it++){
myBoard.step_up();
}
int ad = myBoard.merge_up();
for(int it = 0;it<4;it++){
myBoard.step_up();
}
invalidate();
How to deal this problem? It is very important for me
Update:
The code from onCreate:
GraphicsView myview=new GraphicsView(this);
setContentView(myview);
GraphicsView entire code is too big. The part of it:
public GraphicsView(Context context) { super(context);
this.setOnTouchListener(new OnSwipeTouchListener(getApplicationContext()) {
public void onSwipeTop() {
//above code
}
//other methods
}
protected void onDraw(Canvas canvas)
{
//draw
}
}

Updating Canvas? invalidate()?

Hi im trying to get my app to update a canvas from a custom view i made
This view creates a square with lines and a circle in the center.
I want to press a button and draw random x and y coordinates to the canvas.
Heres My MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// EditText numDart = (EditText) findViewById(R.id.numDarts);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public int convertToDpi(int px){
DisplayMetrics metrics = getResources().getDisplayMetrics();
int unit = metrics.widthPixels/20;
return px * unit;
}
public void drawCanvas(View v){
View view = (View) findViewById(R.id.canView);
Paint black = new Paint();
black.setColor(Color.BLACK);
black.setStyle(Style.FILL);
view.invalidate(); //dont know where to go from here
}
Heres My Custom View:
public CanView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Rect myrect = new Rect();
myrect.set(-10, 10, 10, -10);
Paint blue = new Paint();
Paint white = new Paint();
white.setColor(Color.WHITE);
white.setStyle(Paint.Style.FILL);
Paint black = new Paint();
black.setColor(Color.BLACK);
black.setStyle(Paint.Style.FILL);
blue.setColor(Color.BLUE);
blue.setStyle(Paint.Style.FILL);
canvas.drawRect(myrect, blue);
canvas.drawCircle(convertToDpi(10), convertToDpi(10),convertToDpi(3), white);
canvas.drawLine(convertToDpi(10), 0, convertToDpi(10), convertToDpi(20), black);
canvas.drawLine(0, convertToDpi(10), convertToDpi(20), convertToDpi(10), black);
canvas.scale(5, 5, 0, 0);
}
#Override
public void postInvalidate() { //Logic for redrawig goes here???
// TODO Auto-generated method stub
super.postInvalidate();
}
public int convertToDpi(int px){
DisplayMetrics metrics = getResources().getDisplayMetrics();
int unit = metrics.widthPixels/20;
return px * unit;
}
I dont get how to reference the canvas from my Custom View and change or redraw it. Im assuming you use invalidate(); but im puzzled on how this method works can any1 help me out?
When invalidate is called onDraw is called again, you should also use this.getHolder().addCallback(this); and let your class implement Callback and add the unimplemented methods
I guess you need to draw the view only. First of set your contentview as the View where you are drawing on the canvas. Your are setting your contnet view only as the main layout. If you want to see the View where you drawing on canvas. set that view to your contentView.
setContentView(canView);
Now if you want that button too, then create a relative layout and add the button view and this canView to that relative layout ans set this as your contentView.

Setting size of a triangle (Android)

So, I have created an android activity that draws a triangle on the canvas. I also added 4 menus(Color, Enlarge, Shrink, and Reset) to the VM. The color works fine but I'm not quite sure how to resize a triangle in android once that menu button is pressed.The assignment says to just fix the top point of the triangle, and then change the coordinates of the bottom two points of the triangle. Can anyone point me in the right direction on how to do that in Android?
Here's my code, although the implementation of enlarge, shrink, and reset are set up to work with a circle(project I did before), not a triangle. Please note that the "Color" menu works so no need to do that.
public class MainActivity extends Activity
{
final Context context = this;
private Graphics graphic;
private Dialog radiusDialog; //Creates dialog box declaration
private SeekBar red;
private SeekBar green;
private SeekBar blue;
private Button radiusButton;
private TextView progress1;
private TextView progress2;
private TextView progress3;
private TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
graphic = new Graphics(this); //Create new instance of graphics view
setContentView(graphic); //Associates customized view with current screen
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) //This acts as a menu listener to override
{
switch(item.getItemId()) //returns menu item
{
case R.id.Color:
showDialog();
break;
case R.id.Shrink:
graphic.setRadius(graphic.getRadius() -1);
graphic.invalidate();
break;
case R.id.Enlarge:
graphic.setRadius(graphic.getRadius() +1);
graphic.invalidate();
break;
case R.id.Reset:
graphic.setColor(Color.CYAN);
graphic.setRadius(75);
graphic.invalidate();
break;
}
return super.onOptionsItemSelected(item);
}
void showDialog() //creates memory for dialog
{
radiusDialog = new Dialog(context);
radiusDialog.setContentView(R.layout.draw_layout); //binds layout file (radius) with current dialog
radiusDialog.setTitle("Select Color:");
red = (SeekBar)radiusDialog.findViewById(R.id.seekBar1);
green = (SeekBar)radiusDialog.findViewById(R.id.seekBar2);
blue = (SeekBar)radiusDialog.findViewById(R.id.seekBar3);
progress1 = (TextView)radiusDialog.findViewById(R.id.textView2);
progress2 = (TextView)radiusDialog.findViewById(R.id.textView4);
progress3 = (TextView)radiusDialog.findViewById(R.id.textView6);
mychange redC = new mychange();
red.setOnSeekBarChangeListener(redC);
mychange greenC = new mychange();
green.setOnSeekBarChangeListener(greenC);
tv = (TextView)radiusDialog.findViewById(R.id.textView7);
mychange c = new mychange();
blue.setOnSeekBarChangeListener(c);
radiusButton = (Button) radiusDialog.findViewById(R.id.button1);
radiusButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
int color = Color.rgb(red.getProgress(), green.getProgress(), blue.getProgress());
radiusDialog.dismiss();
setContentView(R.layout.activity_main);
setContentView(graphic);
graphic.setColor(color);//Create new instance of graphics view
graphic.invalidate();
}
});
radiusDialog.show(); //shows dialog on screen
}
public class mychange implements OnSeekBarChangeListener{
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
int color = Color.rgb(red.getProgress(), green.getProgress(), blue.getProgress());
tv.setBackgroundColor(color);
progress1.setText(String.valueOf(red.getProgress()));
progress2.setText(String.valueOf(green.getProgress()));
progress3.setText(String.valueOf(blue.getProgress()));
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
}
}
Graphics Class to draw triangle
public class Graphics extends View
{
private Paint paint;
private int radius;
private int color;
public void setColor(int color)
{
this.color = color;
}
public Graphics(Context context) //creates custom view (constructor)
{
super(context);
paint = new Paint(); //create instance of paint
color = Color.CYAN;
paint.setStyle(Paint.Style.FILL); //draw filled shape
radius = 75;
}
#Override
protected void onDraw(Canvas canvas) //override onDraw method
{
super.onDraw(canvas);
paint.setColor(color);
paint.setStyle(Paint.Style.STROKE);
Path path = new Path();
path.moveTo(230, 200);
path.lineTo(330, 300);
path.lineTo(130, 300);
path.close();
canvas.drawPath(path, paint);
}
void setRadius(int radius)
{
this.radius = radius;
invalidate(); //just like repaint method
}
public int getRadius()
{
return radius;
}
}
If the top coordinate remains fixed, you can change the height of the triangle to shrink/enlarge it.
Lets say the triangle is equilateral - all 3 sides have the same length. In this case:
So if the top vertex coordinates are (x, y), the bottom coordinates will be:
(x - side / 2, y + h)
And:
(x + side / 2, y + h)
So your path code should be written as:
float side = Math.sqrt(3) / 2 * height;
Path path = new Path();
path.moveTo(x, y);
path.lineTo(x - side / 2, y + height);
path.lineTo(x + side / 2, y + height);
path.close();

Categories

Resources