Based on the answer to my previous question, I'm making a heavily-customized scrolling list, and I wish to capture the child view offset (letting the basic Android functionality handle flicking and bouncing on overscroll etc).
The offset however is always returning 0. Ideas greatly appriciated
package com.example.svexample
import android.annotation.TargetApi;
import android.app.ActionBar.LayoutParams;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.widget.ScrollView;
public class ScrollViewTest {
private static final String TAG = ScrollViewTest.class.getSimpleName();
private ScrollView sv;
private View v;
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public ScrollViewTest(Context context) {
v = new View(context);
v.setBackgroundColor(Color.BLUE);
v.setBottom(800); v.setRight(400);
sv = new ScrollView(context);
sv.setBackgroundColor(Color.RED);
sv.setBottom(400); sv.setRight(400);
//The next two lines don't seem to help...
//LayoutParams lp = new LayoutParams(400, 600);
//sv.setLayoutParams(lp);
sv.addView(v);
}
public void draw(Canvas canvas){
sv.draw(canvas);
v.draw(canvas);
Log.d(TAG, "Scroll is: " + sv.getScrollY());
}
}
Turns out I needed to feed my app onTouchEvent to the ScrollView in order for it to be interactive (since it was created programatically). I would have assumed the Android UI elements do this automatically but in this case apparently not.
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
I am trying to create different charts for my App and I use AndroidPlot. I want to swipe between different plots, so that when I swipe left a new chart is drawn for example.
I have implemented OnTouchListener and a function drawChart(String Discipline) that shall draw the chart, however, when drawChart is called from OnTouch, it does not work.
Moreover, if I try to detect an ACTION_MOVE, nothing happens, only ACTION_DOWN is detected. I do not see why.
Here is the code:
import android.content.Intent;
import android.graphics.Color;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import com.androidplot.Plot;
import com.androidplot.xy.BoundaryMode;
import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.PointLabelFormatter;
import com.androidplot.xy.SimpleXYSeries;
import com.androidplot.xy.XYPlot;
import com.androidplot.xy.XYSeries;
import com.androidplot.xy.XYStepMode;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A placeholder fragment containing a simple view.
*/
public class DrawChartsFragment extends Fragment implements View.OnTouchListener{
XYPlot plot;
public DrawChartsFragment() {
}
Number[] getXcoord(int length){
Number[] tmp = new Number[length];
for (int i = 0; i < length; i++){
tmp[i] = i;
}
return tmp;
}
private void drawChart(String Discipline){
plot = (XYPlot)getActivity().findViewById(R.id.plot);
Number[] data = Statistic.getDataPoint(Discipline);
List<Number> list = Arrays.asList(data);
Number[] x = getXcoord(list.size());
XYSeries series = new SimpleXYSeries(Arrays.asList(x),list,Discipline);
LineAndPointFormatter series1Format = new LineAndPointFormatter();
series1Format.setPointLabelFormatter(new PointLabelFormatter());
series1Format.configure(getActivity().getApplicationContext(),
R.xml.line_point_formatter_with_labels);
plot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 5);
plot.setRangeBoundaries(0, 100, BoundaryMode.FIXED);
plot.setRangeStep(XYStepMode.INCREMENT_BY_VAL, 10);
plot.addSeries(series, series1Format);
plot.setTitle(Discipline);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
plot = (XYPlot)getActivity().findViewById(R.id.plot);
// plot.setOnTouchListener(this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_draw_charts, container, false);
rootView.setOnTouchListener(this);
return rootView;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
drawChart("Skeet");
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
MainActivity.showToast("Move");
return true;
}
return false;
return false;
}
}
If I call drawChart("Skeet") from onActivityCreated, it works fine. But when called from OnTouchListener, then I only get a lot of messages like:
Looking up object containing: textPaint.color
Attempting to find getter for textPaint in class com.androidplot.xy.PointLabelFormatter
Invoking getTextPaint on instance of
com.androidplot.xy.PointLabelFormatter
It seems like it cannot read the parameters from the xml-file? Any ideas are appreciated!
/ Erik
Adding the following to the end of drawChart() should get things working:
plot.redraw();
You need to call Plot.redraw() when making changes to series data, add or remove series in a plot or alter display params such as line color, thickness etc. outside of onActivityCreated(). The reason it works when called from onActivityCreated() is because that code runs before Androidplot finishes initialization. Once initialization has completed, redraw() is automatically invoked one time to ensure that the plot is always visible.
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 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
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.