We have one MainActivity.
On this Main I would like to display my SurfaceView, but only if a button was clicked.
So when the main is started and the user clicks one button the SurfaceView should appear and everytim it appears it should excecute the onCreate-Method.
But it did not work.
All of my code is in this constructor:
public GameView(Context context, AttributeSet attrs)
So this one should be usesd, but i don't know what to do :/
EDIT:
Code in XML:
<de.apex.viewer.view.GameView
android:id="#+id/gameView1"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true"
android:layout_marginLeft="94dp" />
Here is some Code from the main:
public void displayGameView(View view)
{ // here I need code to "recreate" my gameView
}
And here some Code from the GameView which should be displayed:
public class GameView extends SurfaceView {
public GameView(Context context, AttributeSet attrs)
{
super(context, attrs);
surfaceHolder = getHolder();
surfaceHolder.addCallback(new SurfaceHolder.Callback()
{
public void surfaceDestroyed(SurfaceHolder holder)
{}
public void surfaceCreated(SurfaceHolder holder)
{
// here is my code I want to execute
Canvas theCanvas = surfaceHolder.lockCanvas(null);
HouseInRow = DefineRowCount(arraylength);
GesamtZahl = HouseInRow*2+HouseInColumn*2;
System.out.println("Houserow: " + HouseInRow);
public void surfaceChanged(SurfaceHolder holder, int format,int width, int height)
{}
});
}
Related
I've read many threads here which discuss how to get view size at runtime yet none of the solutions have worked for me.
GameScreen.java
public class GameScreen extends AppCompatActivity{
// Declare an instance of SnakeView
GameView snakeView;
SurfaceHolder surface;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_screen);
snakeView = (GameView) findViewById(R.id.GameView);
surface = snakeView.getHolder();
snakeView = new GameView(this, surface);
}
where GameView is a view class extending surfaceview. The following is a simplified version of my code detailing the issue. I've omitted the run() method and many others to avoid confusion.
GameView.java
public class GameView extends SurfaceView implements Runnable {
public GameView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public GameView(Context context, SurfaceHolder surfaceholder) {
super(context);
init();
m_context = context;
// Initialize the drawing objects
m_Holder = surfaceholder;
m_Paint = new Paint();
}
private void init(){
surfaceHolder = getHolder();
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
m_Screenheight = height;
m_Screenwidth = width;
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
});
}
However calling getWidth() and getHeight() causes the app to crash.
I know that you have to wait for the view to layout but I've tried all the suggestions but I've tried all the suggestions from other threads to no avail.
My main lack of understanding comes from the fact that I am using implements Runnable in my custom class so I'm not sure where I am allowed to use getWidth or a similar method. I'm new to android in general so please be explicit in your solution.
EDIT:
I should mention that I am using the width and height to form a grid to draw in the surfaceview.
EDIT 2:
See revised code.
If your surface is full screen, you can get the screen sizes.
public GameView(Context context, SurfaceHolder surfaceholder) {
super(context);
init();
m_context = context;
// Initialize the drawing objects
m_Holder = surfaceholder;
m_Paint = new Paint();
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity)context).getWindowManager()
.getDefaultDisplay()
.getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
int width = displayMetrics.widthPixels;
m_ScreenHeight= height;
m_ScreenWidth= width;
}
Sorry for my english. I have activity1, and activity2. In activity1 i have button, when i click this button this button freezes for a few seconds and after this open activity2. To remove a freeze when click button in activity1 I added code that launches the camera in new runOnUiThread but now not called surfaceCreated.
mPreview - my custom surfaceView
mCamera - object camera
My code:
new Thread(new Runnable() {
#Override
public void run() {
CameraActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mPreview.addCamera(mCamera);
mPreview.addParent(CameraActivity.this);
mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mPreview.refreshDrawableState();
mCamera.startPreview();
}
});
}
}).start();
My costom SurfaceView ( i add only important code)
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
public CameraPreview (Context context){
super(context);
}
public CameraPreview(Context context, AttributeSet attrs){
super(context, attrs);
}
public CameraPreview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void addCamera(Camera camera){
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
try {
if(mCamera!=null){
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
} catch (Exception e){
Toast.makeText(this.getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
//code
mCamera.startPreview();
}
}
That's the expected behaviour, the Surface is maintained by the SurfaceView, as a workaround you could check if the surface is valid and has non-0 dimentions and call your surfaceCreated/surfaceChangedfunctions manually
the code you need:
Surface surface = mHolder.getSurface();
if(surface != null && surface.isValid()){
Rect frame = mHolder.getSurfaceFrame();
if(frame.width() > 0 && frame.height() > 0){
surfaceCreated(mHolder);
surfaceChaged(mHolder, PixelFormat.OPAQUE, frame.width(), frame.height()); //pixel format OPAQUE is the default one
}
}
I try to use my own SurfaceView in XML and I am unable to do it. I get NullPointerException.
According internet it should look like this:
Activity:
package editor;
import android.app.Activity;
import android.os.Bundle;
import com.example.balls_menu_v1.R;
public class EditorActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.editor);
EditorView ev = (EditorView) findViewById(R.id.editorView);
}
}
If I comment findViewById I get NullPointerException.
SurfaceView:
package editor;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class EditorView extends SurfaceView {
public EditorView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onFinishInflate() {
super.onFinishInflate();
SurfaceHolder holder = getHolder();
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.GREEN);
holder.unlockCanvasAndPost(canvas);
}
}
Layout: editor.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<editor.EditorView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/editorView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
I found answer: implement SurfaceHolder.Callback, add all 3 constructors of SurfaceView and add getHolder().addCallback(this); to each constructor.
Code:
public class EditorView extends SurfaceView implements SurfaceHolder.Callback{
public EditorView(Context context) {
super(context);
getHolder().addCallback(this);
// TODO Auto-generated constructor stub
}
public EditorView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
// TODO Auto-generated constructor stub
}
public EditorView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
getHolder().addCallback(this);
// TODO Auto-generated constructor stub
}
public void doDraw() {
SurfaceHolder holder = getHolder();
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.GREEN);
holder.unlockCanvasAndPost(canvas);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {}
#Override
public void surfaceCreated(SurfaceHolder holder) {
doDraw();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
}
you can't call Canvas canvas = holder.lockCanvas();`
before the oncreate flow finish,
you should call it after the oncreate finish
I'm working on a Livewallpaper with a Thread Painting all Objects and Custom Objects extended from View. The Problem is that my custom view doesn't fire on click....
Here are the Code Snippeds:
in my WallpaperService Class the OnTouch ist given to my Painting Thread:
#Override
public void onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
painting.doTouchEvent(event);
}
Then in the constructor of my PaintingThread I'm creating instances of my custom view:
public LiveWallpaperPainting(SurfaceHolder surfaceHolder, Context context) {
for(int i = 0; i < numberOfObj;i++ ){
obj.add(new Obj(context,objBitmap, objBitmap2, mCanvasWidth, mCanvasHeight, 32, 32 , 20, 10));
}
Then in the Constructor of my Obj:
super(context);
this.context = context;
this.setEnabled(true);
this.setFocusable(true);
this.setFocusableInTouchMode(true);
this.setClickable(true);
this.setOnClickListener(this);
The Class implements OnClickListener.
But when I'm logging the onClick nothing happens....:
#Override
public void onClick(View v) {
Log.d(TAG, "clicked");
}
I'm getting crazy because I tried so much, but nothing worked... :( Please help me.
I think the OnClick is catched before my Obj can react?? But don't know why....
I hope I gave you all details needed...
Yumi
The following code works. Have you on the Activity a other OnClickListener?
public class CustomView extends View implements OnClickListener {
Paint paint;
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawRect(0.f, 0.f, 240.f, 240.f, paint);
this.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Log.d("CustomView", "Click");
}}
main.xml
<com.examples.view.CustomView
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
I am working on a code where we use canvas to detect the touch on the screen.As of now the canvas is been directly drawn.How to add it as part of a view which comprises of other elements in xml.Here is the code
public class Tutorial2D extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new Panel(this));
}
}
Here is the other part of it
public class Panel extends SurfaceView implements SurfaceHolder.Callback {
private ViewThread mThread;
private ArrayList<Element> mElements = new ArrayList<Element>();
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
mThread = new ViewThread(this);
}
public void doDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
synchronized (mElements) {
for (Element element : mElements) {
element.doDraw(canvas);
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (!mThread.isAlive()) {
mThread = new ViewThread(this);
mThread.setRunning(true);
mThread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mThread.isAlive()) {
mThread.setRunning(false);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (mElements) {
mElements.add(new Element(getResources(), (int) event.getX(), (int) event.getY()));
}
return super.onTouchEvent(event);
}
}
How to add this canvas to the main xml and been displayed over an image,any snippet on this or how should I change working on this code,anything will be greatful.Thanks
Try this constructor for the Panel class:
public Panel(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
mThread = new ViewThread(this);
}
You can use the custom view in xml layout with its package name. For example, in main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello" />
<your.package.name.Panel
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Then, in onCreate of your activity:
setContentView(R.layout.main);