I am new comer to android but not to java. I have been designing UI in android through XML file, in that page i have 3 linear Layouts, in my top layout(first LinearLayout) i have kept some image and in the last layout i have kept some buttons,now i need to place a circle(of red color) in my center layout using canvas,i have written a separate class that extends View where in onDraw(Canvas canvas) ,i have drawn a circle.
package com.project.TargetTrackr3;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class DrawCanvasCircle extends View{
public DrawCanvasCircle(Context mContext) {
super(mContext);
}
public void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
canvas.drawColor(Color.WHITE);
paint.setColor(Color.BLUE);
canvas.drawCircle(20, 20, 15, paint);
}
}
Now i have to bring this canvas to the second layout,my main.xml is shown below
package com.project.TargetTrackr3;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
public class TargetTrackr3Activity extends Activity {
/** Called when the activity is first created. */
protected LinearLayout ll;
DrawCanvasCircle c;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main1); //layouting file
ll = (LinearLayout) findViewById(R.id.LinearLayout_DrawCircle);//This is where i have to bring the canvas
c = new DrawCanvasCircle(this);
...................................
................................
}
}
Here is what I did to include your view.
Start with adding a new layout to your xml file, then you can retrieve that, and then you can add to it like this:
DrawCanvasCircle pcc = new DrawCanvasCircle (this);
Bitmap result = Bitmap.createBitmap(25, 25, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
pcc.draw(canvas);
pcc.setLayoutParams(new LayoutParams(25, 25));
mControls.addView(pcc);
In this example mControls is a layout that is added to the main activity layout.
Related
I have created a view MyToggleButton that extends ToogleButton. I overwrite the Togglebutton's onDraw method to draw a line on the button and to rotate it's text.
Here is MyToggleButton:
package com.example.gl.myapplication;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.widget.ToggleButton;
public class MyToggleButton extends ToggleButton {
public float textRotation=0;
public MyToggleButton(Context context, float rotationValue) {
super(context);
textRotation=rotationValue;
}
#Override
protected void onDraw(Canvas canvas){
TextPaint textPaint = getPaint();
textPaint.setColor(getCurrentTextColor());
textPaint.drawableState = getDrawableState();
canvas.save();
//paint
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(7);
paint.setStrokeCap(Paint.Cap.ROUND);
canvas.drawLine(canvas.getWidth() / 2, canvas.getHeight() / 2, (float) (canvas.getHeight() / 2 + 400), (canvas.getHeight() / 2), paint);
canvas.rotate(textRotation, canvas.getWidth() / 2, canvas.getHeight() / 2);
getLayout().draw(canvas);
canvas.restore();
}
}
After that I want to get a screenshot of and view it and for that I use the takeScreenshot() method that is called by pressing the 3rd button on screen. The screenshot code is based on How to programmatically take a screenshot in Android?. The same approach is followed in other posts on stackoverflow, and in various sites and tutorials I found around.
Here is the MainActivity that I use:
package com.example.gl.myapplication;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AbsListView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//add 3 buttons
addButtons();
}
private void addButtons(){
LinearLayout linear1= (LinearLayout) findViewById(R.id.vert1);
//MyToggleButton with rotated text
MyToggleButton btn1 = new MyToggleButton(this,0);
btn1.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
btn1.setTextOff("Button 1 not rotated");
btn1.setTextOn("Button 1 not rotated");
btn1.setText("Button 1 not rotated");
linear1.addView(btn1);
//MyToggleButton with normal text
MyToggleButton btn2 = new MyToggleButton(this,50);
btn2.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
btn2.setTextOff("Button 2 rotated");
btn2.setTextOn("Button 2 rotated");
btn2.setText("Button 2 rotated");
linear1.addView(btn2);
//button to create screenshot
Button btn3 = new Button(this);
btn3.setText("Create bitmap");
btn3.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
takeScreenshot();
}
});
linear1.addView(btn3);
}
//Screenshotcreator
private void takeScreenshot() {
try {
View v1 = getWindow().getDecorView().getRootView();
// create bitmap screen capture
v1.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
ImageView imageView1 =(ImageView) findViewById(R.id.imageView1);
imageView1.setImageBitmap(bitmap);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
Here is the layout of MainActivity:
<?xml version="1.0" encoding="utf-8"?>
<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: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="com.example.gl.myapplication.MainActivity"
android:id="#+id/relative1">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/vert1">
<ImageView
android:layout_width="wrap_content"
android:layout_height="250dp"
android:id="#+id/imageView1" />
</LinearLayout>
</RelativeLayout>
The problem is that although everything looks ok on the screen, the screenshot's bitmap lacks the drawn line and the rotated text.
What could be the reason for that strange result in the bitmap?
Notice that that the devices back-home-recents buttons are missing from the screenshot, as also the status bar information (time etc). I doubt that this has to do something with my issue. Those elements do not belong in my app so it is expected for them to not appear in the view I get with get with v1 = getWindow().getDecorView().getRootView(); But the canvas on which I draw the rotated text and the line do belong to that view.
My question is: Why does the drawn line and the rotated text do not appear on the screenshot, and how can I modify my code to get a screenshot with them on too?
I don't want to do something that needs a rooted device and also I cannot use MediaProjection API because this was added in API 21 but I want my app to run on android 4.4 (API 19) too. Finally, I am aware of the existence of external libraries such as Android Screenshot Library or this: https://android-arsenal.com/details/1/2793 , but I would rather not use any external library.
P.S. maybe this is related:Surfaceview screenshot with line/ellipse drawn over it
The problem is that both btn1.isDrawingChaceEnabled() and btn2.isDrawingChaceEnabled() return false.
Even if you call setDrawingCacheEnabled(true) on the RootView, it is not set as true recursively on all his Children View (I tested it with Log.d).
That means that the drawing cache of your ToggleButton will be empty as explained in the android.view.View.getDrawingCache() javadoc.
/**
* <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
*
* #return A non-scaled bitmap representing this view or null if cache is disabled.
*
* #see #getDrawingCache(boolean)
*/
So make sure you set setDrawingCacheEnabled(true) for each of the views you are interested in.
For example I added the following lines to your code:
in MainActivity
btn1.setDrawingCacheEnabled(true);
btn2.setDrawingCacheEnabled(true);
And it looks like this
package com.smallfan.museumexhibition.views;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.Toast;
public class CustomDrawableView extends View implements View.OnClickListener {
Drawable drawable;
Paint paint;
String myText;
int x1,y1;
Context context;
public CustomDrawableView(Context context, Drawable mydrawable, int x, int y, String text) {
super(context);
this.myText=text;
this.x1=x;
this.y1=y;
this.paint = new Paint();
this.context=context;
drawable=mydrawable;
drawable.setBounds(x, y, x + drawable.getMinimumWidth(), y + drawable.getMinimumHeight());
setOnClickListener(this);
}
protected void onDraw(Canvas canvas) {
drawable.draw(canvas);
}
#Override
public void onClick(View v)
{
v.setTag(myText);
Toast.makeText(context, "View clicked. "+" tag "+ v.getTag(), Toast.LENGTH_SHORT).show();
}
}
///////////////////////////////////////////////////
package com.smallfan.museumexhibition;
import java.io.InputStream;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MapInActivity extends Fragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.v("MapInActivity", "onCreate()");
}
DrawView drawView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
Log.v("MapInActivity", "onCreateView()");
View v = LayoutInflater.from(getActivity()).inflate(R.layout.indoormap_layout, null);
RelativeLayout maplayout=(RelativeLayout)v.findViewById(R.id.maplayout);
CustomDrawableView mCustomDrawableView = new CustomDrawableView(getActivity(),getResources().getDrawable(R.drawable.ic_launcher),10,10,"Item 1");
maplayout.addView(mCustomDrawableView);
CustomDrawableView mCustomDrawableView1 = new CustomDrawableView(getActivity(),getResources().getDrawable(R.drawable.ic_launcher),50,50,"Item 2");
maplayout.addView(mCustomDrawableView1);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
Log.v("MapInActivity", "onActivityCreated().");
}
//
}
I have to draw a map like this and also show the overlay on tap of any pin like in Google map. I was able to draw views on canvas along with click listeners, but the click listener action is performed by clicking any where on screen and it's just for the view drawn in last. So if any solution then please let me know. Thanks in advance.
Have you heard of GeoFencing ? The only catch is that it works on the principle of a circle. But that should not be that bad, since you can cover the entrance with 2 circles, 1 that covers the breath of the room and includes the entrance door, and the other circle contained within the bigger circle that only covers the door.
Check out A4, I have drawn 2 circles, sorry for a ugly representation.
If a user enters the smaller circle and the bigger circle than he is still in the room. If he enters the smaller circle and exists it (and is not entering the bigger circle) he has exited the room.
Twisted but will work with minimal coding. Just read up geofencing.
Also note geofencing is now merged with LocationClient API's which consume 8 times lesser battery as compared to LocationManager. So go for it.
I'm still learning Android, and I decided to download an example paint application to fiddle with that and learn a bit about how Android handles graphics/drawables/painting. The code I have shows a green and red 'V' in the upper left corner, and a red dot that follows where you touch.
However, I found that the screen is being redrawn each time, so I can't use it as a painting tool. It's almost as if I'm dumping a bucket of white paint over the surface and then redrawing the circle. How can I make it so that the red dot that follows your finger leaves a trail? Here's the code.
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
public class MainActivity extends Activity implements OnTouchListener {
private float x;
private float y;
private int moveX;
Paint paint = new Paint();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyCustomPanel view = new MyCustomPanel(this);
ViewGroup.LayoutParams params =
new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
addContentView(view, params);
view.setOnTouchListener(this);
}
private class MyCustomPanel extends View {
public MyCustomPanel(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.GREEN);
paint.setStrokeWidth(6);
canvas.drawLine(moveX,10,50,50,paint);
paint.setColor(Color.RED);
canvas.drawLine(50, 50, 90, 10, paint);
canvas.drawCircle(50, 50, 3, paint);
moveX++;
canvas.drawCircle(x,y,3,paint);
}
}
public boolean onTouch(View v, MotionEvent event) {
x = event.getX();
y = event.getY();
v.invalidate();
return true;
}
}
For example, save the circles in an ArrayList. Make an ArrayList and save every xy coordinates from touch as a point.The following code is just from scratch, could not test it at the moment, so if anything is not working let me know and I will give a an example when I am at home.
private ArrayList<Point> pointList = new ArrayList<Point>
Then in On Touch:
Point xyPoint = new Point();
xyPoint.x = event.getX();
xyPoint.y = event.getY();
pointList.add(xyPoint);
invalidate();
and in onDraw, do a for-loop to get all points and draw each one:
for(int i=0;i<pointList.size();i++){
Point p = pointList.get(i);
canvas.drawCircle(p.x, p.y, 2, paint);
}
This draws circles with 2px diameter where Your finger touches. But this is just an simple example, there is a lot of more You can do and that look better. You should learn about draw on path and how to draw rects and ovales etc. Here is a good example of how to draw on path:
http://android-er.blogspot.de/2011/08/drawpath-on-canvas.html
I need help to understand what I am doing wrong. I am setting a PNG Image as my background (canvas) and then I want to put another PNG image on top at a particular coordinate. But problem is when I set the background canvas PNG first it stays there but when the other image (on top) loads , the background canvas disappear. So obviously I am not doing something right.
Any suggestion from the android developers community would be highly appreciated.
THANKS!
HERE IS THE CODE BELOW:
StartNewGame.java:
package com.firm.armouredassault;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
public class StartNewGame extends Activity {
MyGame ourView;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
ourView = new MyGame(this);
setContentView(ourView);
}
}
Mygame.java
package com.firm.armouredassault;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.View;
public class MyGame extends View {
Bitmap BTank, TShell;
public MyGame(Context context) {
super(context);
// TODO Auto-generated constructor stub
BTank = BitmapFactory.decodeResource(getResources(), R.drawable.bluetanksm);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.drawBitmap(BTank, 10, 200, null);
}
}
newgame.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/canvas"
android:orientation="vertical" >
</LinearLayout>
write a bitmap on a canvas, pass this canvas to a new canvas with the help of a method and canvas as parameter, then there if you write a new bitbap there on the new canvas , it will be written
I am trying to get a panel which has a canvas containing an image which i will place over another image and when i touch the screen the top(overlaying) image will be erased by means of a PoerterDuffXfermode(PorterDuff.Mode) etc ,, anyway I have the functionality done and dusted thanks to the help of a guy on this forum who provided some code which basically carried out exactly what I needed, but I'm having one slight problem,, the guys implementation of the code, will not allow me to reference the Panel class properly in XML to place the Panel on a pre defined XML (main.xml) file. its giving me an error stating
Custom view Panel is not using the 2- or 3-argument View constructors; XML attributes will not work
This is what my xml looks like on a basic scale (just the view in place within the outer linearlayout).
<com.easyscratch.full.Panel
xmlns:android="http://schemas.android.com/apk/res/android"
android:id ="#+id/easyCustView"
android:layout_width="300dp"
android:layout_height="300dp"
android:visibility="visible"
android:focusableInTouchMode="true"/>
The java is as followed .( PANEL CLASS)
package com.easyscratch.full;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
class Panel extends View
{
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
Bitmap bitmap;
Canvas pcanvas ;
int x = 0;
int y =0;
int r =0;
public Panel(Context context) {
super(context);
Log.v("Panel", ">>>>>>");
setFocusable(true);
setBackgroundColor(Color.GREEN);
// setting paint
mPaint = new Paint();
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setAntiAlias(true);
// getting image from resources
Resources r = this.getContext().getResources();
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.foreground_image);
// converting image bitmap into mutable bitmap
bitmap = Bitmap.createBitmap(295, 260, Config.ARGB_8888);
pcanvas = new Canvas();
pcanvas.setBitmap(bitmap); // drawXY will result on that Bitmap
pcanvas.drawBitmap(bm, 0, 0, null);
}
#Override
protected void onDraw(Canvas canvas) {
// draw a circle that is erasing bitmap
pcanvas.drawCircle(x, y, r, mPaint);
canvas.drawBitmap(bitmap, 0, 0,null);
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// set paramete to draw circle on touch event
x = (int) event.getX();
y = (int) event.getY();
r =20;
// Atlast invalidate canvas
invalidate();
return true;
}
}
BASIC MAIN CLASS CALLING MAIN.XML
package com.easyscratch.full;
import android.app.Activity;
import android.os.Bundle;
public class easyscratch extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
,, If only Someone cud tell me what im doing wrong , or maybe an alternative implementation of the
public Panel(Context context) {
super(context);
anyway thanks alot in advanced really would appriciate some help as soon as possible :)
CHEERS GUYS!
Your constructor for Panel must also, at least, have an AttributeSet field.
public Panel(Context context, AttributeSet attr){
super.(context, attr);