I would like each time I press one of the buttons the rectangles on the screen to change position. Or the entire SurfaceView to refresh.
The app seems to run but the rectangles do not change position with the counter.
Thank you very much.
Hare is the xml code:
<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" >
<SurfaceView
android:id="#+id/surface"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="#string/hello_world"
tools:context=".MainActivity" />
<Button
android:id="#+id/l"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="16dp"
android:text="L" />
<Button
android:id="#+id/r"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView1"
android:layout_alignParentTop="true"
android:layout_marginLeft="19dp"
android:text="R" />
</RelativeLayout>
Here is the Java:
package com.example.rectangle;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
DrawView drawView;
Paint paint = new Paint();
int w, h, edge, axis_w;
int counter;
Button add, sub;
TextView display;
#Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
counter = 0;
add = (Button) findViewById(R.id.r);
sub = (Button) findViewById(R.id.l);
display = (TextView) findViewById(R.id.textView1);
add.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
counter += 10;
display.setText("Total is" + counter);
}
});
sub.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
counter -= 10;
display.setText("Total is" + counter);
}
});
SurfaceView surface = (SurfaceView) findViewById(R.id.surface);
surface.getHolder().addCallback(new Callback() {
public void surfaceCreated(SurfaceHolder holder) {
Canvas canvas = holder.lockCanvas();
w = canvas.getWidth();
h = canvas.getHeight();
edge = 5;
axis_w = 3;
// canvas.drawRect(left, top, right, bottom, paint)
// Background
paint.setColor(Color.rgb(255, 255, 255));
canvas.drawRect(0, 0, w, h, paint);
// Canvas Background Color
paint.setColor(Color.rgb(0, 206, 209));
// Borders
canvas.drawRect(0, 0, w, edge, paint);
canvas.drawRect(0, h - edge, w, h, paint);
canvas.drawRect(0, 0, edge, h, paint);
canvas.drawRect(w - edge, 0, w, h, paint);
// Axis
canvas.drawRect(((w - axis_w) / 2) + counter, 0,
((w + axis_w) / 2) + counter, h, paint);
canvas.drawRect(0, (h - axis_w) / 2, w, (h + axis_w) / 2, paint);
holder.unlockCanvasAndPost(canvas);
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
}
Ok. Try Another solution. Try to make your own View class where you will draw your rectangle. I have prepared some code for you. Customize it to your needs.
Simlpe XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/mainL"
>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World, MainActivity"
android:id="#+id/button"
/>
</LinearLayout>
and java code
public class MainActivity extends Activity
{
MyRectg myRectg;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myRectg = new MyRectg(this);
((LinearLayout)findViewById(R.id.mainL)).addView(myRectg);
((Button)findViewById(R.id.button)).setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0)
{
myRectg.invalidate();
}
});
}
public class MyRectg extends View
{
public MyRectg(Context c)
{
super(c);
}
#Override
public void onDraw(Canvas c)
{
//this simulate new positions calculating
Random rnd = new Random();
Paint p = new Paint();
p.setColor(Color.GREEN);
c.drawRect(rnd.nextFloat()*100, rnd.nextFloat()*500, rnd.nextFloat()*300, rnd.nextFloat()*500, p);
}
}
Now canvas randomly moves when you click the button. Is this what you wanted?
Try to call Invalidate method on SurfaceView to refresh it after each position change.
EDIT:
And move position calculation from surfaceCreated to surfaceChanged method.
Related
I'm trying to build a custom view but for some reason it's not displaying at all.
To save you reading both constructors, I am calling the View constructor without the attr parameter because these should be fetched from the Layout file. Any values that are not fetched from here are set in the view class itself.
My view class:
package mrl233.campustour.AugmentedReality;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.hardware.SensorManager;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import org.w3c.dom.Text;
import java.util.ArrayList;
import java.util.List;
import mrl233.campustour.R;
/**
* TODO: document your custom view class.
*/
public class CameraOverlay extends View {
private float mAzimuth;
private float mPitch;
private float mRoll;
private String mTextString;
private int mTextColor = Color.RED;
private float mTextDimension = 80;
private Drawable mTextDrawable;
private float mTextSize = 29;
private TextPaint mTextPaint;
private float mTextHeight = 0;
private float mTextWidth;
public CameraOverlay(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.CameraOverlay,
0, 0);
try {
mTextString = a.getString(R.styleable.CameraOverlay_exampleString);
mAzimuth = a.getFloat(R.styleable.CameraOverlay_exampleFloat_X, 0);
mPitch = a.getFloat(R.styleable.CameraOverlay_exampleFloat_Y, 0);
mRoll = a.getFloat(R.styleable.CameraOverlay_exampleFloat_Z, 0);
} finally {
a.recycle();
}
init();
}
public CameraOverlay(Context con, float azimuth, float pitch, float roll) {
this(con,null);
this.mAzimuth = azimuth;
this.mPitch = pitch;
this.mRoll = roll;
TypedArray a = con.getTheme().obtainStyledAttributes(
null,
R.styleable.CameraOverlay,
0, 0);
try {
mTextString = a.getString(R.styleable.CameraOverlay_exampleString);
mAzimuth = a.getFloat(R.styleable.CameraOverlay_exampleFloat_X, 0);
mPitch = a.getFloat(R.styleable.CameraOverlay_exampleFloat_Y, 0);
mRoll = a.getFloat(R.styleable.CameraOverlay_exampleFloat_Z, 0);
} finally {
a.recycle();
}
init();
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
invalidate();
int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop();
int paddingRight = getPaddingRight();
int paddingBottom = getPaddingBottom();
int contentWidth = getWidth() - paddingLeft - paddingRight;
int contentHeight = getHeight() - paddingTop - paddingBottom;
canvas.drawText("wsfsefseefsfsef",
paddingLeft + (contentWidth - mTextWidth),
paddingTop + (contentHeight + mTextHeight)
,mTextPaint);
}
}
This is my view layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="#+id/overlay" >
<mrl233.campustour.AugmentedReality.CameraOverlay
android:background="#ccc"
android:layout_width="300dp" android:layout_height="300dp" android:paddingLeft="20dp"
android:paddingBottom="40dp" custom:exampleDimension="24sp" custom:exampleColor="#33b5e5"
custom:exampleString="Hello, CameraOverlay"
custom:exampleFloat_X="0.1"
custom:exampleFloat_Y="0.5"
custom:exampleFloat_Z="1"/>
</FrameLayout>
I am adding this view to to an activity which has it's own view. This is the Activity class's onCreate method which is where I try to add the view.
#Override
#SuppressWarnings("deprecation")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_augment);
preview = (FrameLayout) findViewById(R.id.camera_preview);
mPreview = new CameraPreview(this, camera);
mCameraOverlay = new CameraOverlay(this, 0, 0, 0);
preview.addView(mPreview);
preview.addView(mCameraOverlay);
preview.bringChildToFront(mCameraOverlay);
}
The layout of this activity class:
<?xml version="1.0" encoding="utf-8"?>
<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"
app:layout_behavior="#string/appbar_scrolling_view_behavior" tools:showIn="#layout/augment"
tools:context="mrl233.campustour.Activities.Augment">
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<!--<SurfaceView-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="match_parent"-->
<!--android:id="#+id/surfaceView"/>-->
<mrl233.campustour.AugmentedReality.CameraOverlay
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
</RelativeLayout>
I see two problems here. You shouldn't be calling invalidate() in onDraw method cause it causes view to redraw itself(infinite loop). Secondly getWidth() might be 0 there. You might want to get canvas width from onSizeChanged method
private int width;
private int height;
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
...
int contentWidth = width - paddingLeft - paddingRight;
...
}
try playing with hardcoded sizes cause currently you might be drawing that text offscreen or giving it too little space(it might help you find the problem).
Smallest customView I can Think of would be:
public class CustomView extends View {
private TextPaint paint;
public CustomView(Context context) {
super(context);
paint = new TextPaint(Paint.LINEAR_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
paint.setTextSize(20);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText("Hello", 20, 20, paint);
}
}
and init it:
preview.addView(new CustomView(this));
There are few more smaller problems but it might get you going
I have an bitmap that I want to apply an alpha mask to. I know I can easily use Porter Duff mode to do that with another bitmap, but I want to programmatically create the alpha mask because it needs to change continually. So, I'm trying to use a path to create it, but I can't make the connection between the finished path and creating the bitmap to use from that path.
Here is my 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="${relativePackage}.${activityClass}" >
<SeekBar
android:id="#+id/seekBar_percent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:progress="50" />
<ImageView
android:id="#+id/imageView_canvas"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/seekBar_percent"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
Here is my main activity:
package com.wheeler.daniel.xxx;
import android.app.Activity;
import android.os.Bundle;
import android.view.Display;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
public class MainActivity extends Activity {
PathRectangle alphaPath;
ImageView canvas;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
canvas = (ImageView) findViewById(R.id.imageView_canvas);
canvas.post(new Runnable()
{
#Override
public void run() {
Display display = getWindowManager().getDefaultDisplay();
int canvasWidth = display.getWidth();
int canvasHeight = display.getHeight();
alphaPath = new PathRectangle(getApplicationContext(), canvas, canvasWidth, canvasHeight);
}
});
SeekBar percentBar = (SeekBar) findViewById(R.id.seekBar_percent);
percentBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser){
alphaPath.updatePercent(progress);
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
}
I created a class to draw my path (a basic rectangle to cover the image) called PathRectangle:
public class PathRectangle extends View {
ImageView layoutCanvas;
Bitmap canvasBitmap;
Paint paint;
Path path;
float width;
float height;
int percent;
Canvas tempCanvas;
public PathRectangle(Context context, ImageView canvasImage, float width, float height)
{
super(context);
layoutCanvas = canvasImage;
path = new Path();
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(1);
paint.setStyle(Paint.Style.FILL);
this.width = width;
this.height = height;
percent = 50;
Bitmap.Config config = Bitmap.Config.ARGB_8888;
canvasBitmap = Bitmap.createBitmap((int)width, (int)height, config);
tempCanvas = new Canvas( canvasBitmap );
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
path.reset();
path.moveTo(0,0);
path.lineTo(percent, 0);
path.lineTo(percent, height);
path.lineTo(0, height);
tempCanvas.drawPath(path, paint);
layoutCanvas.setImageBitmap(canvasBitmap);
}
public void updatePercent(int newPercent)
{
percent = (int) (width * (newPercent * .01));
invalidate();
}
}
This is just my testing to generate the Bitmap, but nothing is displayed in my ImageView. I feel like by drawing the path to the tempCanvas isn't actually drawing it to the bitmap I used in the creation of the tempCanvas.
Example of what I want:
Source Bitmap
Alpha Mask to create
Result
here is my code for mainactivity: ResizeLineActivity.java
in which i can increase the line width on lineincr button click and line width is decreasing on linedecr button click but the problem is the decreased line width is only get displayed on lineincr button clik. I don't understand what is wrong in the code. Cab anybody explain or correct this code to show decreased line on linedecr button click?
package edu.interview;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
public class ResizeLineActivity extends Activity {
DrawLine drawLine;
Button Lineincr;
Button linedecr;
LinearLayout.LayoutParams layoutParams;
int i=0;
static float x1=50;
static float y1=100;
static float x2=90;
static float y2=100;
static int temp=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Lineincr =(Button)(findViewById(R.id.btn_incr));
linedecr= (Button)findViewById(R.id.btn_decr);
final LinearLayout linearltdrawLine=(LinearLayout)findViewById(R.id.linearlayout_showLineView);
// linearltdrawLine.addView(new DrawLine(this, 50, 100, 100, 100));
Lineincr.setOnClickListener(new View.OnClickListener() {
LinearLayout.LayoutParams layoutParams=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
#Override
public void onClick(View v) {
// temp=++i;
// TODO Auto-generated method stub
linearltdrawLine.removeAllViews();
Toast.makeText(getApplicationContext(), "hello Line", Toast.LENGTH_SHORT).show();
linearltdrawLine.addView(new DrawLine(getApplicationContext(), x1, y1, x2, y2));
int width1=linearltdrawLine.getWidth();
/* TextView txtv=(TextView) findViewById(R.id.linearlayout_showLineView);
txtv.setBackgroundColor(Color.CYAN);
txtv.setText("Insteas of line");*/
linearltdrawLine.invalidate();
linearltdrawLine.refreshDrawableState();
// linearltdrawLine.addView(txtv,layoutParams);
linearltdrawLine.setVisibility(View.GONE);
//linearltdrawLine.setVisibility(View.VISIBLE);
// linearltdrawLine.invalidate();
// linearltdrawLine.removeView(new DrawLine(getApplicationContext(), x1, y1, x2, y2));
for(i=0;i<=1;++i){
x2=x2+1;
linearltdrawLine.setVisibility(View.VISIBLE);
linearltdrawLine.addView(new DrawLine(getApplicationContext(), x1, y1, x2, y2));
// linearltdrawLine.refreshDrawableState();
}
}
});
linedecr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v1) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "Line is decreasing", Toast.LENGTH_SHORT).show();
linearltdrawLine.addView(new DrawLine(getApplicationContext(), x1, y1, x2, y2));
linearltdrawLine.invalidate();
linearltdrawLine.refreshDrawableState();
//linearltdrawLine.setVisibility(View.GONE);
for(i=1;i>0;i--){
linearltdrawLine.removeView(new DrawLine(getApplicationContext(),x1,y1,x2,y2));
x2=x2-1;
linearltdrawLine.invalidate();
linearltdrawLine.addView(new DrawLine(getApplicationContext(), x1, y1, x2, y2));
linearltdrawLine.setVisibility(View.VISIBLE);
}
}
});
}
}
DrawLine.java
package edu.interview;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.content.Context;
import android.view.View;
import android.widget.LinearLayout;
import android.graphics.Color;
public class DrawLine extends View{
private final float X1,Y1,X2,Y2;
private final Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
public DrawLine(Context context,float x1,float y1,float x2, float y2) {
// TODO Auto-generated consructor stub
super(context);
this.X1=x1;
this.Y1=y1;
this.X2=x2;
this.Y2=y2;
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
paint.setTextSize(20);
paint.setColor(Color.RED);
canvas.drawLine(X1, Y1, X2, Y2, paint);
}
}
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"
android:weightSum="1"
android:background="#BEE40F" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello"
/>
<LinearLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:id="#+id/linearlayout_showLineView" android:orientation="vertical" android:layout_weight="0.81" android:weightSum="1">
<LinearLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:id="#+id/linearLayout_showtxt" android:orientation="vertical" android:layout_weight="0.26"></LinearLayout>
</LinearLayout>
<RelativeLayout android:id="#+id/relativeLayout1" android:background="#android:color/white" android:layout_width="fill_parent" android:layout_height="50dp" android:layout_weight="0.06">
<Button android:layout_height="wrap_content" android:id="#+id/btn_incr"
android:layout_width="wrap_content" android:text="Line++"
android:layout_alignParentTop="true" android:layout_alignParentRight="true"
android:layout_marginRight="106dp" android:layout_alignParentBottom="true"
>
</Button>
<Button android:layout_height="wrap_content" android:id="#+id/btn_decr"
android:layout_width="wrap_content" android:text="Line --"
android:layout_toLeftOf="#+id/btn_decr" android:layout_marginRight="19dp"
android:layout_alignParentBottom="true" android:layout_alignParentTop="true">
</Button>
</RelativeLayout>
</LinearLayout>
So basically i want to use a xml layout, but i also want a canvas where i can have graphics performed. What i did was make a view in my xml layout as you can see below. Then in my application i made the view draw the canvas, but it is not working. I'm not sure if my method for solving this is completely wrong or what. So please just take a look at my code and tell me if you see a quick fix or if you have a better method. Thanks in advance I really appreciate it.
<?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" >
<Button
android:id="#+id/bTest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<View
android:id="#+id/vMain"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
that is the xml layout
package sm.view.test;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Button;
public class ViewActivity extends Activity implements OnTouchListener {
/** Called when the activity is first created. */
View v;
Button b;
boolean isRun =true;
SurfaceHolder ourHolder;
Thread ourThread;
Canvas canvas;
boolean isTure = true;
TheSurface ourSurfaceView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
b= (Button) findViewById(R.id.bTest);
v = (View) findViewById(R.id.vMain);
canvas = new Canvas();
ourSurfaceView = new TheSurface(this);
ourSurfaceView.setOnTouchListener(this);
v.draw(canvas);
// v.setBackgroundColor(Color.BLUE);
}
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
ourSurfaceView.pause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
ourSurfaceView.resume();
}
public boolean onTouch(View arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
return false;
}
public class TheSurface extends SurfaceView implements Runnable{
public TheSurface(Context context) {
super(context);
ourHolder= getHolder();
}
public void resume(){
isRun= true;
ourThread = new Thread(this);
ourThread.start();
}
public void pause(){
isRun = false;
while(true){
try {
ourThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
ourThread= null;
}
public void run() {
// TODO Auto-generated method stub
Paint textPaint = new Paint();
textPaint.setColor(Color.WHITE);
while(isTure){
if(!ourHolder.getSurface().isValid())
continue;
//v.draw(canvas);
canvas = ourHolder.lockCanvas();
canvas.drawLine(0, 0, canvas.getWidth(), canvas.getHeight(), textPaint);
ourHolder.unlockCanvasAndPost(canvas);
v.draw(canvas);
}
}
}
}
Start here (and this needs your input as well for the namespace portion "yourProjectNamespace"):
<?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" >
<Button android:id="#+id/bTest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<sm.view.test.TheSurface android:id="#+id/vMain"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
In your TheSurface
Implement the overideable routines:
public TheSurface(Context C){
super(C);
// Other setup code you want here
}
public TheSurface(Context C, AttributeSet attribs){
super(C, attribs);
// Other setup code you want here
}
public TheSurface(Context C, AttributeSet attribs, int defStyle){
super(C, attribs, defStyle);
// Other setup code you want here
}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Paint textPaint = new Paint();
textPaint.setColor(Color.WHITE);
canvas.drawLine(0, 0, canvas.getWidth(), canvas.getHeight(), textPaint);
// Other drawing functions here!!!
}
This should get your drawing done!!!
Also in my case, you dont have to implement this as a SurfaceView, you could just implement it as a View, and it does not need to implement runnable!!!
I'm not 100% sure I understand what you are trying to do, but based on the fact that you don't seem to be doing anything with the canvas after you call View.draw() I believe you may be confused. View.draw(Canvas) draws the View onto the Canvas, it doesn't alter the view.
However, if you create the canvas from a bitmap you could then set the bitmap as an ImageView's image:
Bitmap bm = Bitmap.createBitmap( x-size, y-size, Config.ARGB_8888);
Canvas c = new Canvas(bm);
Paint textPaint = new Paint();
textPaint.setColor(Color.WHITE);
canvas.drawLine(0, 0, canvas.getWidth(), canvas.getHeight(), textPaint);
ImageView iView = (ImageView) view;
iView.setImageBitmap(bm);
However, this is a less correct way than to implement your own View:
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
((MyView)view).mContextVariable = true; //or false, etc
//you might not need this invalidate, because the click event probably causes and invalidate to be called
view.invalidate();
}
}
class MyView extends View
{
Paint myPaint;
boolean mContextVariable;
public MyView(Context context)
{
super(context);
textPaint = new Paint();
textPaint.setColor(Color.WHITE);
}
#Override
protected void onDraw(Canvas canvas)
{
if(mContextVariable)
{
canvas.drawLine(0, 0, canvas.getWidth(), canvas.getHeight(), textPaint);
}
else
{
//draw something else
}
canvas.drawText("testing", 0,0, textPaint);
}
}
I'm drawing some graphics and i would like to add a couple of buttons to it. But with the surface view how do we add these buttons programatically ?
Enclose your surfaceView with a FrameLayout in your xml Layout. Then add your buttons to the same FrameLayout. Make sure they are placed below the surface view so they get drawn on top of it. (Might be a good idea to bundle them in another Layout and add that to the FrameLayout.)
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView android:id="#+id/surfaceView1" android:layout_width="wrap_content" android:layout_height="wrap_content"></SurfaceView>
<LinearLayout android:id="#+id/linearLayout1" android:layout_width="wrap_content" android:layout_height="wrap_content">
<Button android:text="Button" android:id="#+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<Button android:text="Button" android:id="#+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
</LinearLayout>
</FrameLayout>
Thank you so much Androidica..
Your xml has helped me to figure out the following solution programatically without using any xml..
public class LudoActivity extends Activity implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
FrameLayout game = new FrameLayout(this);
GameView gameView = new GameView (this);
LinearLayout gameWidgets = new LinearLayout (this);
Button endGameButton = new Button(this);
TextView myText = new TextView(this);
endGameButton.setWidth(300);
endGameButton.setText("Start Game");
myText.setText("rIZ..i");
gameWidgets.addView(myText);
gameWidgets.addView(endGameButton);
game.addView(gameView);
game.addView(gameWidgets);
setContentView(game);
endGameButton.setOnClickListener(this);
}
public void onClick(View v) {
Intent intent = new Intent(this, LudoActivity.class);
startActivity(intent);
// re-starts this activity from game-view. add this.finish(); to remove from stack
}
}
while GameView is;
public class GameView extends SurfaceView {
public GameView(Context context) {
super(context);
/*
* your code
*/
}
}
Make your own button:
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
public class GButton
{
public Matrix btn_matrix = new Matrix();
public RectF btn_rect;
float width;
float height;
Bitmap bg;
public GButton(float width, float height, Bitmap bg)
{
this.width = width;
this.height = height;
this.bg = bg;
btn_rect = new RectF(0, 0, width, height);
}
public void setPosition(float x, float y)
{
btn_matrix.setTranslate(x, y);
btn_matrix.mapRect(btn_rect);
}
public void draw(Canvas canvas)
{
canvas.drawBitmap(bg, btn_matrix, null);
}
}
on touch event:
float x = ev.getX();
float y = ev.getY();
if (my_button.btn_rect.contains(x, y))
{
// handle on touch here
}
alternatively, even better, if you want to also rotate the button it will not be axis-aligned, then use the invert matrix, instead of mapRect map the touch points x,y:
float pts[] = {x, y};
my_button.invert_matrix.mapPoints(pts);
if (my_button.btn_rect.contains(pts[0], pts[1])
{
// handle on touch here
}
We can use frame layout for surface view drawing very easily .
like this
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/frameLayout"
android:layout_width="fill_parent"
android:layout_height="430dp"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:gravity="center_horizontal"
android:layout_gravity="bottom"
android:background="#c2300f">
<Button
android:id="#+id/buttonColor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Color" />
</LinearLayout>
</LinearLayout>
And Main activity is
package com.example.surfacetuto;
import android.app.Activity;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener{
DrawingSurface ds;
FrameLayout frm;
Button btnC;
int color=0xfff00000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ds=new DrawingSurface(this);
setContentView(R.layout.activity_main);
frm=(FrameLayout)findViewById(R.id.frameLayout);
frm.addView(ds);
btnC=(Button)findViewById(R.id.buttonColor);
btnC.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.buttonColor:
Toast.makeText(getApplicationContext(), "Color", 2).show();
ds.colorNew();
break;
default:
break;
}
}
}
And Drawing Surface class is
package com.example.surfacetuto;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {
Canvas cacheCanvas;
Bitmap backBuffer;
int width, height, clientHeight;
Paint paint;
Context context;
SurfaceHolder mHolder;
public DrawingSurface(Context context) {
super(context);
this.context = context;
init();
}
public DrawingSurface(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
private void init() {
mHolder = getHolder();
mHolder.addCallback(this);
}
int lastX, lastY, currX, currY;
boolean isDeleting;
#Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
int action = event.getAction();
switch(action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
lastX = (int) event.getX();
lastY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
if(isDeleting) break;
currX = (int) event.getX();
currY = (int) event.getY();
cacheCanvas.drawLine(lastX, lastY, currX, currY, paint);
lastX = currX;
lastY = currY;
break;
case MotionEvent.ACTION_UP:
if(isDeleting) isDeleting = false;
break;
case MotionEvent.ACTION_POINTER_DOWN:
cacheCanvas.drawColor(Color.WHITE);
isDeleting = true;
break;
case MotionEvent.ACTION_POINTER_UP:
break;
}
draw();
return true;
}
protected void draw() {
if(clientHeight==0) {
clientHeight = getClientHeight();
height = clientHeight;
backBuffer = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888);
cacheCanvas.setBitmap(backBuffer);
cacheCanvas.drawColor(Color.WHITE);
}
Canvas canvas = null;
try{
canvas = mHolder.lockCanvas(null);
canvas.drawBitmap(backBuffer, 0,0, paint);
}catch(Exception ex){
ex.printStackTrace();
}finally{
if(mHolder!=null) mHolder.unlockCanvasAndPost(canvas);
}
}
private int getClientHeight() {
Rect rect= new Rect();
Window window = ((Activity)context).getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight= rect.top;
int contentViewTop= window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleBarHeight= contentViewTop - statusBarHeight;
return ((Activity)context).getWindowManager().getDefaultDisplay().
getHeight() - statusBarHeight - titleBarHeight;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
width = getWidth();
height = getHeight();
cacheCanvas = new Canvas();
backBuffer = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888);
cacheCanvas.setBitmap(backBuffer);
cacheCanvas.drawColor(Color.WHITE);
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(10);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
draw();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
public void colorNew() {
// TODO Auto-generated method stub
paint.setColor(Color.GRAY);
}
}