I'm stucked in this for almost a month. I have a perfect chart in my android code using 'afreechart', however, the library does not seem to have support for exporting the chart as an image yet (since it's based on 'jfreechart' and this one does the job).
I tried to get the view of the chart, convert it into canvas and save using the compress functions of the bitmap library, however everytime i try this i get a totally black image as a result. I tried this same method and it works for the other views of my code (simple views, like linearlayout and relativelayout).
After that i tried to create a routine to make a screenshot of the chart activity and close that activity after that. But I couldn't find a way to do that by code, the closest i got was with monkeyrunner.
So i gave up of this idea and tried to look for other libraries, such as 'kichart', 'achartengine', etc, but none of them seem to do the job for, i'm freaking out and i thought that exporting the chart to an image wouldn't be that hard... any ideas?
When i set a background color for the layout, the returned image is a full rectangle with the color of the background, so it's getting the layout, just not the chart.
My Code:
package com.kichart;
import java.io.File;
import java.io.FileOutputStream;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
public class Main extends Activity {
LinearLayout ll;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
float[] values = new float[] { 2.0f,1.5f, 2.5f, 1.0f , 3.0f };
String[] verlabels = new String[] { "great", "ok", "bad" };
String[] horlabels = new String[] { "today", "tomorrow", "next week", "next month" };
GraphView graphView = new GraphView(this, values, "GraphViewDemo",horlabels, verlabels, GraphView.BAR);
ll = new LinearLayout(this);
ll.addView(graphView);
Draw2d d = new Draw2d(this);
setContentView(d);
//setContentView(graphView);
}
public class Draw2d extends View {
public Draw2d(Context context) {
super(context);
setDrawingCacheEnabled(true);
}
#Override
protected void onDraw(Canvas c) {
ll.setBackgroundColor(Color.WHITE);
ll.measure(MeasureSpec.getSize(ll.getWidth()), MeasureSpec.getSize(ll.getHeight()));
ll.layout(400, 400, 400, 400);
ll.draw(c);
try {
getDrawingCache().compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(new File("/mnt/sdcard/graph2.png")));
} catch (Exception e) {
Log.e("Error--------->", e.toString());
}
super.onDraw(c);
}
}
}
You can get a image bitmap from a view by doing:
Bitmap bitmap;
chart.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(chart.getDrawingCache());
chart.setDrawingCacheEnabled(false);
if you can't call getDrawingCache on the chart, try to place it inside a layout like RelativeLayout or something like that. and call it on the layout.
After that you can save it as a image..
If the image is still black, you need to make sure the chart is created before getting the bitmap.
Hope this will help you
Related
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 trying to draw different random values from an array, but linking them with lines, so it looks likes the values of a continue function. I have done it quite good with this app:
package android.nacho.Graphic2D;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import java.util.Random;//included random
public class Graphic2D extends Activity{
DrawView drawView;
//private Button btnAsyncTask;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int randomInt;
//note a single Random object is reused here
Random randomGenerator = new Random();
int Maxsize=800;
int[] randomNumbers= new int[Maxsize];
for (int idx = 1; idx < Maxsize-1; ++idx){
randomInt = randomGenerator.nextInt(100);
randomNumbers[idx]=randomInt;
System.out.println("Random number: "+randomInt);
}
drawView = new DrawView(Graphic2D.this, randomNumbers, Maxsize);
drawView.setBackgroundColor(Color.WHITE);
setContentView(drawView);
}
}
package android.nacho.Graphic2D;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class DrawView extends View {
Paint paint = new Paint();
int[] values;
int Size, Offset;
public DrawView(Context context, int[] datainBytes, int size) {
super(context);
values=datainBytes;
Size=size;
paint.setColor(Color.BLACK);
}
#Override
public void onDraw(Canvas canvas) {
int cont2;
for(int cont=0; cont<Size-(1); cont++)
{
cont2=cont+1;
canvas.drawLine(cont, 500-(values[cont]) , cont+1, 500-(values[cont2]), paint);
}
}
}
The thing is, now I want to dram much more points, but in a dinamicall way so the new value is the one most at the right, the rest of the values move one pixel to the left and the one most of the left just don't appear. I was planning to this with a loop in the main Activity, so in each iteration the random values are all the same but the last one, and the others have move one position to the left in the array. The final effect should be something like a video.
But there is a problem, do App don't draw this dinamically, it just draw the last iteration of the loop. ¿Could anyone help me to solve this?
I was thinking in using AsyncTask for that, doing the points generation in the backgroun and sending the result to the update so draw in, but the script was a mess that didn't work, so I prefer to don't upload it.
Thank you very much for any suggestion.
I'm new to the Android SDK so I'm trying to figure this out. I have read the documentation and a text book and they haven't been particularly helpful in this matter.
I'm just trying to draw a simple rectangle in a linear layout on the screen. I can't get the shape to show up, however, when I add text to this layout in the same fashion, the text does show up. What am I missing?
package jorge.jorge.jorge;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ShapesActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ShapeDrawable rect = new ShapeDrawable(new RectShape());
rect.getPaint().setColor(Color.GREEN);
ImageView view1 = new ImageView(this);
view1.setImageDrawable(rect);
LinearLayout frame = (LinearLayout)findViewById(R.id.linear1);
frame.addView(view1);
// TextView tx = new TextView(this);
//
// tx.setText("Hello World");
//
// frame.addView(tx);
}
}
The Shape is usually used for making a background to some View. Its width and height is the same of the view that is using it. Then, if this view has no width and height, It'll have no width and height, too.
Basically, I think that your ImageView has no width and height, then it's invisible.
You can see how to set it programatically here:
Set ImageView width and height programmatically?
But, I recomend you to make the layout in XML's way.
I'm trying to develop an android application that is basically for drawing shapes.I want the user to make gesture on the screen and the shape that is more closely matching to gesture should be drawn on the screen.
In my application,I can detect the gesture that is being performed on the screen like circle,line,rectangle etc. but there is some problem with my code.It actually detects the gesture and draws the respective shape but it happens only once.
For example. If I draw Line on the screen then line is drawn on my view but after that If I draw circle or rectangle etc then gesture is recognized but the shape is not drawn there.
Here is the full code of that
package com.pck.ShapeMaker;
import java.util.ArrayList;
import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.Prediction;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.Toast;
public class GestureDetection extends Activity {
private GestureLibrary gLib;
private LinearLayout l1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gesture);
l1 = (LinearLayout) findViewById(R.id.playArea);
gLib = GestureLibraries.fromRawResource(this, R.raw.gestures);
if (!gLib.load())
finish();
GestureOverlayView gesturesView = (GestureOverlayView) findViewById(R.id.gestures);
myGestureHandler handler = new myGestureHandler();
gesturesView.addOnGesturePerformedListener(handler);
}
class myGestureHandler implements OnGesturePerformedListener{
public void onGesturePerformed(GestureOverlayView gestureView, Gesture gesture){
ArrayList<Prediction> predictions = gLib.recognize(gesture);
if (predictions.size() > 0 && predictions.get(0).score > 1.0) {
String action = predictions.get(0).name;
if ("l".equals(action)) {
Line line = new Line(getApplicationContext(),20,230,200,230);
l1.addView(line);
} else if ("r".equals(action)) {
Rectangle rect = new Rectangle(getApplicationContext());
l1.addView(rect);
Toast.makeText(getApplicationContext(), "rect", Toast.LENGTH_SHORT).show();
} else if ("t".equals(action)) {
Triangle tri = new Triangle(getApplicationContext(), 300,300,250, 350, 350, 350);
l1.addView(tri);
Toast.makeText(getApplicationContext(), "trianlge", Toast.LENGTH_SHORT).show();
}else if ("c".equals(action)) {
Circle c1 = new Circle(getApplicationContext(),50,50,30);
l1.addView(c1);
Toast.makeText(getApplicationContext(), "circle", Toast.LENGTH_SHORT).show();
}else if ("d".equals(action)) {
Toast.makeText(getApplicationContext(), "diamond", Toast.LENGTH_SHORT).show();
}
}
}
}
}
It looks like your code will produce an ever-increasing number of views within the LinearLayout. Is that what you intended? If not, you could try removing the obsolete views from the layout before adding the new one. The problem may be that there is no space in the layout for subsequent views after the first one is added.
Also, dynamically adding views like this, seems like an odd way to draw graphics. Why not define a single custom view to cover all types of drawing and include that statically in XML? Your onGesturePerformed() method would then call some method of your view to specify the type of drawing to be performed, then call invalidate() to trigger redrawing. The onDraw() method of your view would then draw whichever graphic was just specified.
I am using RelativeLayout to position views at precise locations on the screen. This works as expected when using a view that say, draws a rectangle. But when using Android views like EditText, they are drawn shorter than specified by about 8 units. Clicking outside of the drawn EditText (but within the parameters specified by RelativeLayout) will, in fact, hit the EditText.
Here is some code to illustrate what I mean:
package com.DrawDemo;
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.View;
import android.widget.EditText;
import android.widget.RelativeLayout;
public class DrawDemo extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
RelativeLayout l = new RelativeLayout(this);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(100,100);
lp.leftMargin = 50;
lp.topMargin = 50;
DemoView demoview = new DemoView(this);
l.addView(demoview, lp);
EditText editText = new EditText(this);
l.addView(editText, lp);
setContentView(l);
}
private class DemoView extends View
{
public DemoView(Context context)
{
super(context);
}
#Override protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.GREEN);
canvas.drawPaint(paint);
}
}
}
If you execute this, you will notice that the EditText is noticeably shorter than the rectangle. I've tried mucking with onMeasure, setMinimumXXX, and just about everything else I can think of. So far, the only thing that works with some level of success is to just add 8 or so pixels to the height (8 seems to work better than trying a percentage of the height).
Next task will be to step into the source but was wondering if somebody has already solved this.
Thanks.
It's just because of the actual EditText background image that's used. Buttons are the same way, for some reason Google decided to draw the 9-patch background images with some extra transparent padding pixels. Really, the only solution, if it's a problem, would be to draw your own 9-patch, or modify the existing Android 9-patch to remove the extra pixels.