Android - invalidate() doesn't call my onDraw in CustomView - android

I have an content_main.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="#layout/activity_main">
<com.example.CustomView
android:id="#+id/customView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout >
In MainActivity.java, in onCreate I call the CustomView:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
customView = new CustomView(this, attributeSet);
customView.init();
}
And in CustomView, I have an onDraw:
#SuppressLint("DrawAllocation")
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLUE);
drawValidMoves(canvas, squareSize);
}
in MainActivity, the onTouch
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
int x = (int)event.getX();
int y = (int)event.getY();
String text = customView.isTouched(x, y, customView.getSquareSize());
Toast.makeText(this, text, Toast.LENGTH_LONG).show();
}
return super.onTouchEvent(event);
}
is calling an method from CustomView.java - isTouched that change some things in a matrix of drawed elements and after that, I'm making some:
setWillNotDraw(false);
invalidate();
but my game doesn't reach onDraw again...
If I'm calling in onCreate directly the CustomView, the invalidate works:
customView = new CustomView(this, attributeSet);
customView.init();
setContentView(customView);
but I don't have the toolbar anymore, and I need that
LATER EDIT:
content_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/linearLayoutId"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="#layout/activity_main">
<com.example.clotz.CustomView
android:id="#+id/customView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout >
MainActivity.java - onCreate - I moved the data from init method into constructor and get rid of init.
public class MainActivity extends AppCompatActivity {
CustomView customView;
#SuppressLint("WrongViewCast")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
customView = findViewById(R.id.customView);
}
But customView is null now in onTouchEvent:
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
int x = (int)event.getX();
int y = (int)event.getY();
String text = customView.isTouched(x, y, customView.getSquareSize());
Toast.makeText(this, text, Toast.LENGTH_LONG).show();
}
return super.onTouchEvent(event);
}

#Mike M helped me with this and I put in content_main.xml the id of the linearLayout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/linearLayoutId"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="#layout/activity_main">
<com.example.clotz.CustomView
android:id="#+id/customView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout >
in MainActivity.java - onCreate (I moved the data from init method into constructor and get rid of init) and I created the customview with findViewById(R.id.customView);
public class MainActivity extends AppCompatActivity {
CustomView customView;
#SuppressLint("WrongViewCast")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
customView = findViewById(R.id.customView);
}
And the problem was in CustomView.java, I forgot to pass attributeSet to the superclass:
public CustomView(Context context, AttributeSet attributeSet) {
super(context);
initializeMovedMatrix();
setInitialPositionForPieces();
// create the Paint to set its color
paint = new Paint();
piecesMoves = new PiecesMoves(this);
}
and putting it, combined with customView = findViewById(R.id.customView);
super(context, attributeSet);
Solved the problem.
Thanks again MikeM!

you cannot delete super.onDraw(canvas) in onDraw method.
#SuppressLint("DrawAllocation")
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLUE);
drawValidMoves(canvas, squareSize);
}

Related

Android Floating Button not showing

I try to make drawing page with canvas and add floating button in corner for some actions. But it is not appearing.
This is my classes
DrawView.java
public class DrawView extends View implements View.OnTouchListener {
private List<Point> points = new ArrayList<>();
private Paint paint = new Paint();
public DrawView(Context c) {
super(c);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
paint.setColor(Color.BLACK);
}
#Override
public void onDraw(Canvas canvas) {
for (Point point : points) {
canvas.drawCircle(point.x, point.y, 30, paint);
}
}
public boolean onTouch(View view, MotionEvent event) {
Point point = new Point();
point.x = event.getX();
point.y = event.getY();
points.add(point);
invalidate();
return true;
}}
And Main activity
public class DrawingPage extends AppCompatActivity {
private DrawView drawView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawing_page);
drawView = new DrawView(getApplicationContext());
drawView.setBackgroundColor(Color.WHITE);
setContentView(drawView);
drawView.requestFocus();
}}
XML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
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"
tools:context="reminder.com.picsartdrawing.DrawingPage">
<android.support.design.widget.FloatingActionButton
android:id="#+id/myFAB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#mipmap/ic_launcher"
app:elevation="4dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
But floating button is not appearing, any solutions?
Screenshot
EDIT!!!
in Activity's onCreate method I have changed this, and now I have drawing canvas page with button.
RelativeLayout layout = (RelativeLayout) findViewById(R.id.layout);
drawView = new DrawView(getApplicationContext());
drawView.setBackgroundColor(Color.WHITE);
drawView.requestFocus();
assert layout != null;
layout.addView(drawView);
In onCreate() you replace 2 times with setContentView() the "main" view, so try with only this:
setContentView(R.layout.activity_drawing_page);
You need to add this in the onCreate method of your activity class:
FloatingActionButton fab = (FloatingActionButton) findViewById (R.id.fab);
fab.setOnClickListener (new View.OnClickListener () {
#Override
public void onClick (View view) {
Snackbar.make (view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction ("Action", null).show ();
}
});

How to instantiate a view inside a Frame layout?

This is my MainActivity:
public class MainActivity extends Activity {
PieMenu pieMenu;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pieMenu = new PieMenu(getApplicationContext());
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
{
pieMenu.addPieMenu(x,y);
}
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
}
return false;
}
}
PieMenu:
public class PieMenu extends FrameLayout{
private Context _context;
public PieMenu(Context context) {
super(context);
_context = context;
// TODO Auto-generated constructor stub
}
public void addPieMenu(int x, int y){
Toast.makeText(_context, "text",Toast.LENGTH_LONG).show();
PieItem pieView = new PieItem(_context,x,y,2);
//FrameLayout.LayoutParams lyp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
//pieView.setLayoutParams(lyp);
addView(pieView);
invalidate();
}
}
PieItem.java:
public class PieItem extends View{
private final float x;
private final float y;
private final int r;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public PieItem(Context context, float x, float y, int r) {
super(context);
mPaint.setColor(0xFFFF0000);
this.x = x;
this.y = y;
this.r = r;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(x, y, r, mPaint);
}
}
MainActivity.xml:
<FrameLayout 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" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="#string/hello_world" />
</FrameLayout>
Everytime I touch the scree, the toast is being called but the circle isn't being instantiated. Where am I going wrong?
easiest way to fix this, add view in onCreate:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pieMenu = new PieMenu(getApplicationContext());
FrameLayout fl = (FrameLayout)findViewById(R.id.layout);
fl.addView(pieMenu);
}
and add id to your main activity xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
You aren't adding pieMenu to any of the views in your layout (R.layout.activity_main)
What does your activity_main.xml look like?
You didn't add created PieMenu to activity layout. You need to call something like this in onCreate method:
view.addView(pieMenu);
Or add your PieMenu to you activity_main layout.

Padding does not work as expected in android

padding does not work as expected in custom ViewGroup
Hi:
My layout have the following structure:
RelativeLayout(with padding)
MainView(ViewGroup)
And the activety_main.xml:
<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"
android:background="#ffffff"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
tools:context=".MainActivity" >
<com.example.testandroid.MainView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
MainView:
public class MainView extends ViewGroup {
public MainView(Context context, AttributeSet as) {
super(context);
addView(new MyView(context, null));
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.drawColor(Color.GREEN);
super.dispatchDraw(canvas);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0, len = getChildCount(); i < len; i++) {
View v = getChildAt(i);
v.layout(l,t,r,b);
}
}
}
MyView:
public class MyView extends SurfaceView implements Callback {
public MyView(Context contex, AttributeSet as) {
super(contex, as);
getHolder().addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
refresh();
}
private void refresh() {
SurfaceHolder holder = getHolder();
synchronized (holder) {
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
try {
Paint p = new Paint();
p.setColor(Color.RED);
canvas.drawCircle(10, 10, 10, p);
} finally {
holder.unlockCanvasAndPost(canvas);
}
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
refresh();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
Now, this is what I got now:
As you can see, the viewgroup I created MainView has a background of green.
And MainView add a MyView dynamically whose background is black here.
Now, the problem is that what the MyView have a padding relative to MainView? Because I want it take all the space of MainView, that's to say, the greed should be invisible.
Why?
But
When you layout your children, it needs to be relative to your position.
To fill yourself you would do child.layout(0, 0, getWidth(), getHeight());.
Try doing this ...
<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"
android:layout_margin="16dp"
tools:context=".MainActivity" >
<com.example.testandroid.MainView
android:layout_width="match_parent"
android:layout_height="600dp"
/>
</RelativeLayout>

How to use my own view in an Android layout?

I have created one view, view code is,
public class MyDraw extends View{
//List<Point> mArryLstpoints = new ArrayList<Point>();
Paint paint =new Paint();
Paint mPaintAlphabet = new Paint();
public MyDraw(Context context) {
super(context);
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
// TODO Auto-generated constructor stub
}
public MyDraw(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
mPaintAlphabet.setDither(true);
mPaintAlphabet.setColor(0xFFFF0000);
mPaintAlphabet.setStyle(Paint.Style.STROKE);
mPaintAlphabet.setStrokeJoin(Paint.Join.ROUND);
mPaintAlphabet.setStrokeCap(Paint.Cap.ROUND);
mPaintAlphabet.setStrokeWidth(3);
mPaintAlphabet.setTextSize(400);
}
public void onDraw(Canvas canvas){
canvas.drawColor(Color.GRAY);
canvas.drawText("A",100,350, mPaintAlphabet);
System.out.println("in on draw");
for(Point mPoint:MyAlphabetsActivity.mArryLstpoints)
canvas.drawCircle(mPoint.x, mPoint.y, 12, paint);
}
}
I want use this view in layout and I want to set background images for the view. I am using following code,
<?xml version="1.0" encoding="utf-8"?>
<com.qteq.myalphabets.MyDraw
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" ></com.qteq.myalphabets.MyDraw>
My activity class is,
public class MyAlphabetsActivity extends Activity {
/** Called when the activity is first created. */
MyDraw mMyDraw;
Button mBtnOk;
AttributeSet attributeSet;
public static List<Point> mArryLstpoints = new ArrayList<Point>();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/*
* getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
* WindowManager.LayoutParams.FLAG_FULLSCREEN);
*/
/*
* mMyDraw=new MyDraw(this); setContentView(mMyDraw);
* mMyDraw.requestFocus();
*/
mMyDraw = (MyDraw) findViewById(R.id.mMyDraw_layout);
mMyDraw.bringToFront();
mMyDraw.requestFocus();
mMyDraw.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
Point mPoint=new Point();
mPoint.x=event.getX();
mPoint.y=event.getY();
System.out.println("in on touch");
mArryLstpoints.add(mPoint);
System.out.println("Array list is-----"+mArryLstpoints);
setContentView(R.layout.main);
return true;
}
});
// setContentView(R.layout.main);
}
}
class Point{
public float srtx;
float x, y;
#Override
public String toString() {
System.out.println("in on point");
return x + ", " + y;
}
}
and Displaying and onTouch Method called only one time.
You are Adding view with fill_parent width and height , so no space to add other views like buttons and images .
one of the possible implementation
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.qteq.myalphabets.MyDraw
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_contentt" ></com.qteq.myalphabets.MyDraw>
<Button/>
<ImageView/>
</LinearLayout>
Dont forget to add constructor
public MyDraw(Context context, AttributeSet attributeSet) {
super(context, ttributeSet);
in MyDraw.java
******** *editing* ******
in onTouch()
return super(v, event) instead of true ;
also check if you need to write setOnTouchListener() to view or canvas .
You can place your view within a layout in your XML and there can be other elements, as well, within that layout. You can set layout background to something, too.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#drawable/mybackground">
<com.qteq.myalphabets.MyDraw
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>

How to stack a canvas and a button?

I want to write the following application. There is a Canvas
and a Button stacked vertically in a LinearView. When the button
is pressed the first time a circle is drawn in the canvas, then
if pressed again the circle disappears. The circle must appear
centered in its space.
Any ideas?
Thanks,
JG
This should work
Custom View class
public class DrawView extends View {
private Canvas viewCanvas;
public DrawView(Context context) {
super(context);
setLayoutParams(new LayoutParams(LinearLayout.LayoutParams.FILL_PARENT
,LinearLayout.LayoutParams.FILL_PARENT));
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint();
p.setColor(Color.RED);
canvas.drawCricle(getWidth()/2,getHeight()/2,50,null);
viewCanvas = canvas;
}
public clearCircle(){
viewCanvas.drawColor(Color.BLACK);
}
}
Activity class should look like this
public class KeyboardTopDemo extends Activity {
private FrameLayout container;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ss);
container = (FrameLayout)findViewById(R.id.sc);
container.addView(new DrawView(this));
}
public void clearHandler(View target){
container.getChildAt(0).clearCircle();
}
}
This is the layout xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<FrameLayout android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="0dip" android:id="#+id/sc"
android:scrollbars="horizontal" android:layout_weight="1.0">
<ImageView android:layout_width="fill_parent"
android:layout_height="fill_parent" android:src="#drawable/chips"/>
</FrameLayout>
<Button android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="Clear" android:onClick="clearHandler"/>
</LinearLayout>

Categories

Resources