Redraw canvas in Android - android

I am making an Android 2.2 application using Eclipse. My application should draw
images by clicking on buttons.
I have two buttons at the bottom of the screen, and I need to draw the shape in the same screen that has the buttons. I used FrameLayout in which the shapes are drawn.
My problem is, the two shapes are overwriting, so I need to redraw the canvas.
My Code
package draw.tab;
import android.app.Activity;
//import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
public class DrawActivity extends Activity implements OnClickListener
{
DrawView drawview;
CircleView circleView;
FrameLayout Frame;
Button square,circle;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Frame=(FrameLayout)findViewById(R.id.MyFrame);
drawview=new DrawView(this);
circleView=new CircleView(this);
square=(Button)findViewById(R.id.buttonTest);
square.setOnClickListener(this);
circle=(Button)findViewById(R.id.circleButton);
circle.setOnClickListener(this);
}
public void onClick(View v)
{
switch (v.getId()) {
case R.id.circleButton:
Frame.addView(circleView);
/*circleView.setBackgroundColor(Color.rgb(40,100,20));
circleView.findViewById(R.id.CircleViewId);
setContentView(circleView);*/
break;
case R.id.buttonTest:
Frame.addView(drawview);
/*drawview.setBackgroundColor(Color.WHITE);
drawview.findViewById(R.id.DrawViewId);
drawview.layout(400,0,200,450);
setContentView(drawview);*/
break;
}
}
}
DrawView.java
package draw.tab;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
public class DrawView extends View
{
Paint paint=new Paint();
Path pat=new Path();
public DrawView(Context context)
{
super(context);
paint.setColor(Color.RED);
paint.setStyle(Style.STROKE);
//context.clearRect(70,140,400,450);
//pat.addRect(50,40,250,400,Path.Direction.CW);
}
public DrawView(Context con,AttributeSet atts)
{
super(con,atts);
}
#Override
public void onDraw(Canvas canvas)
{
//canvas.drawPath(pat,paint);
canvas.drawLine(20,40,450,40,paint);//horizontal top
canvas.drawRect(70,140,400,450,paint);
canvas.drawLine(20,40,20,600,paint);//vertical left
canvas.drawLine(20,600,450,600,paint);//horizontal bottom
canvas.drawLine(450,40,450,600,paint);//vertical right
//this.invalidate();
}
}
CircleView.java
package draw.tab;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
public class CircleView extends View
{
Paint p=new Paint();
Path path=new Path();
public CircleView(Context context)
{
super(context);
p.setColor(Color.BLUE);
p.setStyle(Style.STROKE);
//path.addCircle(250,250,50,Path.Direction.CW);
}
public CircleView(Context con,AttributeSet atts)
{
super(con,atts);
}
public void onDraw(Canvas c)
{
//c.drawPath(path,p);
//c.save();
c.drawLine(20,40,450,40, p);//horizontal top
c.drawCircle(250,350,100,p);
c.drawLine(20,40,20,600,p);//vertical left
c.drawLine(20,600,450,600,p);//horizontal bottom
c.drawLine(450,40,450,600,p);//vertical right
//c.restore();
this.invalidate();
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:visibility="visible"
android:id="#+id/MyFrame"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<draw.tab.DrawView
android:id="#+id/DrawViewId"
android:layout_width="320dp"
android:layout_height="600dp">
</draw.tab.DrawView>
<draw.tab.CircleView
android:id="#+id/CircleViewId"
android:layout_width="320dp"
android:layout_height="600dp">
</draw.tab.CircleView>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:gravity="bottom">
<Button
android:layout_height="wrap_content"
android:text="Circle"
android:id="#+id/circleButton"
android:layout_width="160dp">
</Button>
<Button
android:layout_height="wrap_content"
android:text="Square"
android:id="#+id/buttonTest"
android:layout_width="160dp">
</Button>
</LinearLayout>
</FrameLayout>
The above is all my code. The shapes are overwriting, so I want to remove and redraw the canvas or redraw without overwriting.

Try calling invalidate() on your view.

Call canvas.save() then do drawing then call canvas.restore(). Also depends on the bitmaps you are drawing. The bitmaps should have a transparent background.
Edit
Call canvas.drawColor(Color.White); //Or whichever bg color before drawing the bitmap.
Edit
In drawview try this
canvas.drawRect(getLeft(), getTop(), getright() , getBottom() ,paint);
Similarly in CircleView
canvas.drawCircle(getLeft()+getwidth()/2, getTop()+getheight()/2, 100, paint);
One last try. Set children gravity..
<draw.tab.DrawView
android:id="#+id/DrawViewId"
android:layout_width="320dp"
android:layout_height="600dp"
android:layout_gravity="left">
</draw.tab.DrawView>
<draw.tab.CircleView
android:id="#+id/CircleViewId"
android:layout_width="320dp"
android:layout_height="600dp"
android:layout_gravity="right">
</draw.tab.CircleView>

Related

Cannot implement linerGradient() in TextView inside onCreate() method

I want to implement linearGradient() in my textView. I want it in a way so that when the activity loads up, the linearGradient() gets applied on my textview. I was able to do it in a button click listener, but the linear gradient does not work whenever I implement it in the onCreate() method. Below is my xml layout:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical" >
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="70sp" />
<Button
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="63dp"
android:text="Apply Gradient Text" />
</RelativeLayout>
MainActivity.java file:
import android.app.Activity;
import android.graphics.Point;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener {
private TextView tv;
private Button btn;
private int mWidth;
private int mHeight;
private Shader shader;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView)findViewById(R.id.tv);
btn=(Button)findViewById(R.id.btn);
btn.setOnClickListener(this);
tv.setText(" Instagram ");
Typeface face=Typeface.createFromAsset(getAssets(), "fonts/billabong.ttf");
tv.setTypeface(face);
}
public void onClick(View view) {
mWidth=tv.getWidth();
mHeight=tv.getHeight();
Point size = new Point(mWidth,mHeight);
GradientManager gm= new GradientManager(getApplicationContext(),size);
shader=gm.getRandomLinearGradient();
tv.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
tv.getPaint().setShader(shader);
}
}
GradientManager.java file:
import android.content.Context;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Point;
import android.graphics.Shader;
public class GradientManager {
private Point mSize;
public GradientManager(Context context, Point size){
this.mSize = size;
}
protected LinearGradient getRandomLinearGradient(){
LinearGradient gradient = new LinearGradient(0, 0, mSize.x, mSize.y,
new int[] {Color.parseColor("#6656C8"), Color.parseColor("#8E33A9"),Color.parseColor("#BB328C"), Color.parseColor("#ED4B3E"),
Color.parseColor("#FA8031"), Color.parseColor("#FEC65C"), Color.parseColor("#FFD374") },null,
Shader.TileMode.MIRROR
);
return gradient;
}
}
Screenshot when activity starts:
Screenshot when I press the button:
What I want to implement is given below (I removed the button):
MainActivity.java file:
import android.app.Activity;
import android.graphics.Point;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
private TextView tv;
private int mWidth;
private int mHeight;
private Shader shader;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView)findViewById(R.id.tv);
tv.setText(" Instagram ");
Typeface face=Typeface.createFromAsset(getAssets(), "fonts/billabong.ttf");
tv.setTypeface(face);
mWidth=tv.getWidth();
mHeight=tv.getHeight();
Point size = new Point(mWidth,mHeight);
GradientManager gm= new GradientManager(getApplicationContext(),size);
shader=gm.getRandomLinearGradient();
tv.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
tv.getPaint().setShader(shader);
}
}
The contents of GradientManager.java is unchanged, Only the button is removed from my layout. The above code does not show any gradient color, instead It displays the whole textView with the first color of the linear gradient color parameter [Color.parseColor("#6656C8")]. This is my screenshot:
Can someone please help me with the code? What am I missing? Any help is appreciated.
You are using tv.getWidth and getHeight during onCreate. At that time TextView is not measured yet therefore those values are not valid. İf you have to get width and height for gradient you should apply your gradient after measure step is done(i.e. using ongloballayoutlistener).

Strange behavior with Android view.invalidate()

I have 3 custom views placed vertically in a LinearLayout, they are used to display different dynamic info, so they're supposed be invalidated and redrawn at different time. But I found the view invalidation is out of usual expectation, that is: if you invalidate the top view,all 3 views are invalidated at the same time, if you invalidate the middle view, the middle and bottom views are invalidated, the top one is not, if you invalidate the bottom view, only the bottom view itself is invalidated, this is what I want, so what happened with the first 2 cases ? I searched and got similar questions like:
https://stackoverflow.com/questions/26192491/invalidate-one-view-force-other-views-invalidate-too-how-separating-that
Android Invalidate() only single view
but it seems no exact answer. I post my code here, any comment is appreciated.
TestView.java
package com.vrb.myview;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
public class TestView extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onTest(View view){
MyView1 mv1 = (MyView1)findViewById(R.id.mv1);
MyView1 mv2 = (MyView1)findViewById(R.id.mv2);
MyView1 mv3 = (MyView1)findViewById(R.id.mv3);
mv1.invalidate(); // all 3 views are invalidated
// mv2.invalidate(); // mv2 and mv3 are invalidated
// mv3.invalidate(); // only mv3 is invalidated,this is what I want
}
}
MyView1.java
package com.vrb.myview;
import java.util.Random;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class MyView1 extends View {
Rect rc=null;
Paint p=null;
Random r;
public MyView1(Context ctx){
super(ctx);
rc = new Rect();
p = new Paint();
r = new Random();
}
public MyView1(Context ctx, AttributeSet set){
super(ctx, set);
rc = new Rect();
p = new Paint();
r = new Random();
}
public void onDraw(Canvas canvas){
if(canvas.getClipBounds(rc)){
Log.d("MyView1","id="+getId()+" Rect: "+rc.left+","+rc.top+","+rc.right+","+rc.bottom);
p.setColor(Color.argb(0xff, Math.abs(r.nextInt())%255, Math.abs(r.nextInt())%255, Math.abs(r.nextInt())%255));
canvas.drawRect(rc, p);
}else{
Log.d("MyView1","id="+getId()+" Rect=null");
}
}
}
main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/root"
android:orientation="vertical"
tools:context="com.vrb.myview.TestView" >
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="#+id/mv1" />
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="#+id/mv2" />
<com.vrb.myview.MyView1
android:layout_width="match_parent"
android:layout_height="100px"
android:id="#+id/mv3" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Invalidate"
android:onClick="onTest"
android:id="#+id/btn" />
</LinearLayout>
You shouldn't rely on the count or the time of the calls to onDraw() for the internal state of your View. Move the p.setColor() call to a separate public method, and call invalidate() at the end of it. For example:
public class MyView1 extends View {
...
public void changePaint() {
p.setColor(Color.argb(0xff, Math.abs(r.nextInt()) % 255, Math.abs(r.nextInt()) % 255, Math.abs(r.nextInt()) % 255));
invalidate();
}
}
Then in your onTest() method:
public void onTest(View view) {
MyView1 mv1 = (MyView1)findViewById(R.id.mv1);
...
mv1.changePaint();
...
}

Shape Drawable View in XML

I'm using the shapedrawable example word for word (nearly) and can't seem to call a shapedrawable class in xml. The only extra step stated by the documentation was to override the View(Context, AttributeSet), which I think I did. The docs I'm referring to are here: http://developer.android.com/guide/topics/graphics/2d-graphics.html Here is my code.
AndroidTest.java
package com.android.test;
import android.app.Activity;
import android.os.Bundle;
public class AndroidTest extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
ShapeSquare.java
package com.android.test;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.util.AttributeSet;
import android.view.View;
public class ShapeSquare extends View {
private ShapeDrawable mDrawable;
public ShapeSquare(Context context, AttributeSet attrs) {
super(context, attrs);
int x = 10;
int y = 10;
int width = 300;
int height = 50;
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds(x, y, x + width, y + height);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<com.android.test.shapedrawable.ShapeSquare
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
The error is a force quit error and I can't figure out where the problem lies. The shape properties will be dictated by user input (eventually), so the shape needs to be created in a class as opposed to all xml.
Figured out the problem here. I had to remove "shapedrawable" from:
<com.android.test.shapedrawable.ShapeSquare
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
Apparently, that was just the location of the demo. I thought it was referencing the class somehow.

InflateException (Error inflating class) when using custom widget in xml

I created a custom imageview. But I get an InflateException when I try to run this. Can someone help me solve this?
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/herinnering_background">
<be.test.ArrowImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/kompas_arrow_car"
/>
</FrameLayout>
package be.test;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.widget.ImageView;
public class ArrowImageView extends ImageView{
public ArrowImageView(Context context) {
super(context);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
Paint paint = new Paint(Paint.LINEAR_TEXT_FLAG);
paint.setColor(Color.GREEN);
paint.setTextSize(12.0F);
canvas.drawText("Hello World in custom view", 100, 100, paint);
}
}
I think the problem is that you need to implement a constructor with the AttributeSet because this is the one used by the LayoutInflator:
ImageView(Context context, AttributeSet attrs)

Android inflating xml layout generates RuntimeException

I'm new to Android and i'm trying to inflate a layout in xml but i get a RuntimeException. I have cut out almost everything except for my activity class and the class extending SurfaceView.
Can anyone tell me what i'm doing wrong?
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.hj.Panel
android:id="#+id/SurfaceView01"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
Rita.java:
package com.hj;
import android.app.Activity;
import android.os.Bundle;
public class Rita extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Panel.java:
package com.hj;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceView;
class Panel extends SurfaceView {
private Paint mPaint;
public Panel(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
mPaint = new Paint();
canvas.drawRect(0, 0, 322, 644, mPaint);
}
}
In order to make your code run I had to do the following:
1) change "match_parent" to "fill_parent"
2) add constructor
public Panel(Context context, AttributeSet atts) {
super(context, atts);
}
You may want to try that
You should always post a stack trace when you report an exception. (Run adb logcat on the command line, or view the logcat window in eclipse).
Without that, my best guess is that it should be fill_parent, not match_parent.

Categories

Resources