Detect Touch on Surfaceview android - android

I'm creating a camera app and need to detect Touch on surfaceView which is camera preview. I want to set focus of camera where user touch. But Right i just only need to detect touch place.
Here is my preview class code.
public class Preview extends SurfaceView implements SurfaceHolder.Callback {
public Preview(Context ctx, SurfaceView surfaceView) {
super(ctx);
init(surfaceView);
}
private void init(SurfaceView surfaceView){
mSurfaceView = surfaceView;
final SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
surfaceHolder.addCallback(this);
}
public void setCamera(){
mCamera = Camera.open()
mCamera.setPreviewDisplay(mSurfaceView.getHolder());
mCamera.startPreview();
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i(TAG, "onInterceptTouchEvent");
return true;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.i(TAG, "onTouchEvent");
return super.onTouchEvent(event);
}
// Other code.... like override methods etc
MainActivity
// inside onCreate() method
preview = new Preview(this, surfaceView);
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.mainLayout);
mainLayout.addView(preview);
preview.setCamera();
// Other codes .....
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout">
<SurfaceView
android:id="#+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
I added onTouchEvent and onInterceptTouchEvent But both are not working. Whenever I touched on sufaceView nothing show in Log I think I'm missing some thing, can you please let me know ?

preview = new Preview(this, surfaceView);
preview.setCamera();
There is just two line code in MainActivity initilizing the Preview and setCamera() nothing else.
Why you do not see onTouchEvent and onInterceptTouchEvent logs?
I assume, that you haven't added that layout to your view hierarchy.
rootView.addView(preview);
After adding it you should see touch event logs.
But that's not what you actually expect to do, because you have just incorrectly "wrapped" your SurfaceView inside a Java class, which yet doesn't mean that touch events on your SurfaceView would be reflected in your logs.
What you really want is to extend SurfaceView and override those touch events there. Now you would receive correct touch events. Then make sure you are inflating your custom SurfaceView into view hierarchy.
Or, second approach, you can add SurfaceView as a child of your ViewGroup:
yourCustomViewGroup.addView(surfaceView);

There are a few issues with your extended class, in that it does not include all required override methods. However I will assume this is still being developed.
In theory this should work:
preview.setOnClickListener( new OnClickListener(){
#Override
public void onClick() {
//do stuff
}
});
I have not tested it, but as this is extending ViewGroup, this should work.
Note: You probably will need to add this
android:clickable="true"
To your 'Preview' layout, to allow the click to be processed.
Hope that helps.

Related

Using personal SurfaceView on LinearLayout

I'm currently developing an Android App, using a personal SurfaceView and double buffering. However I'm facing a little problem with my code.
In one hand I have an xml view, based on LinearLayout hierarchy. When I instantiate my activity, I set my contentView on this xml. The problem is then that my double buffering don't works anymore. Thread is running but nothing is displayed.
In the other hand, I set my contentView with a new personal SurfaveView element and display works fine. But of course, I cannot access anymore to the other elements of my LinearLayout.
Actually, I would like to set my contentView on my xml view AND keep my display working.
I hope I was clear enough, thank you for your answers!
Here is my activity:
public class MainController extends Activity {
#Override
protected void onCreate(final Bundle p_savedInstanceState) {
super.onCreate(p_savedInstanceState);
setContentView(R.layout.main_controller_activity);
this.drawableView = (MCustomDrawableView) findViewById(R.id.drawingBox);
...
}
...
}
My surface view:
public class MCustomDrawableView extends SurfaceView {
public MCustomDrawableView(Context p_context, AttributeSet p_attributes) {
super(p_context, p_attributes);
this.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(final SurfaceHolder p_holder) {
try {
// Instantiating a new thread
thread = new MBufferingThread(getInstance());
thread.start();
} catch (Exception exception) {
exception.printStackTrace();
}
}
#Override
public void surfaceChanged(final SurfaceHolder p_holder, int p_format, int p_width, int p_height) {...}
#Override
public void surfaceDestroyed(final SurfaceHolder p_holder) {...}
});
// Setup drawing options
setupDrawing();
}
...
}
And my xml view:
<LinearLayout 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:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:background="#color/app_background"
tools:context=".MainController">
<com.iskn.calligraphy.models.draw.MCustomDrawableView
android:id="#+id/drawingBox"
style="#style/DrawingBox" />
<SeekBar
android:id="#+id/brushSize"
style="#style/SizeSeekBar" />
<SeekBar
android:id="#+id/brushOpacity"
style="#style/OpacitySeekBar" />
</LinearLayout>
EDIT:
After further researches and analyses, it appears clearly that:
setContentView(R.layout.main_controller_activity): in this case I get all the elements from my activity, but the MCustomDrawableView display nothing.
setContentView(new MCustomDrawableView(getApplicationContext())): on that case, MCustomDrawableView is working well (it displays what I want), but I don't have the others View from my main_controller_activity
In both cases:
my thread is running and works well.
my drawing function is called as well, with the holder.lockCanvas() and holder.unlockCanvasAndPost(bufferCanvas) methods.
Well, I found a functionnal solution :
I think the problem was coming from the MCustomDrawableView initialization . I created a new instance of that class from the onCreate method , and not from the xml file . Then, I set it to the contentView:
protected void onCreate(Bundle p_savedInstanceState) {
super.onCreate(p_savedInstanceState);
setContentView(R.layout.main_controller_activity);
// Instantiate drawable object & set style properties
this.drawableView = new MCustomDrawableView(getApplicationContext());
FrameLayout.LayoutParams style = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
// Add the drawable view to the main_activity
addContentView(this.drawableView, style);
}
But this way raises a new problem. The added view is on the top, which means that all the others View are hided. I solved this with bringToBack(this.drawableView) below method:
private void bringToBack(View p_view) {
// Get parent from the current view
ViewGroup viewGroup = ((ViewGroup) p_view.getParent());
int childrenCount = viewGroup.indexOfChild(p_view);
for(int cpt = 0; cpt < childrenCount; cpt++) {
// Move the child to the top
viewGroup.bringChildToFront(viewGroup.getChildAt(cpt));
}
}
It brings back the provided view to the background position. I also had to set the LinearLayout's alpha to 0.
I'm still open to other solutions!

How to use android.view.SurfaceView

I'm trying to use the SurfaceView widget. I have a class
public class OurView extends SurfaceView implements Runnable {
public OurView(Context context) {
super(context);
Log.d("OurView", "Yay We started");
}
#Override
public void run() {
}
}
So I have a SurfaceView widget in my Activity's XML. I then try to bind it in the onCreate method
TheView = (OurView) findViewById(R.id.theSurfaceView);
The problem is here I get an error that I can't cast OurView to android.view.SurfaceView.
I know usually I could just do this to the view itself, in the onCreateMethod
TheView = new OurView(this);
setContentView(TheView);
The thing is I don't want to do this, I don't want to draw on my whole activity I just want to draw on the SurfaceView widget that i've put on the layout. How would I do that?
You should put your customized SurfaceView com.xx.OurView in your layout, not SurfaceView.

Specific Portion of the Screen Dedicated to SurfaceView

What I wanted to achieve is this:
I wanted to have a specific portion of the screen to be my SurfaceView. I will use this SurfaceView for some animations. But I wanted to include some Views like TextView and RadioButtonGroup beside my SurfaceView.
So my question is, is this possible? I looking for sample android source code about 'animating sprites', but I couldn't find any activity that incorporates both TextViews and SurfaceView. All are extending SurfaceView. If this is possible, how do I do it? Do you have sample source codes that I can try?
try this i am not extending surfaceview.
public class Preview_can_work extends Activity {
private SurfaceView surface_view;
SurfaceHolder.Callback sh_ob = null;
SurfaceHolder surface_holder = null;
SurfaceHolder.Callback sh_callback = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
surface_view = new SurfaceView(getApplicationContext());
addContentView(surface_view, new LayoutParams(50, 50));
if (surface_holder == null) {
surface_holder = surface_view.getHolder();
}
sh_callback = my_callback(); // CREATING CALLBACK FOR YOUR SURFACE.
surface_holder.addCallback(sh_callback);
}
// THIS FUNCTION RETURNS CALLBACK OBJECT FOR SURFACEVIEW.
SurfaceHolder.Callback my_callback() {
SurfaceHolder.Callback ob1 = new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
};
return ob1;
}
}
now you can simply add any textview or button on your layout it should work.
Note:- I am creating surface dynamically. In your case what you can do is you can create everything in xml file. Instead of creating surfaceview create video view.
SurfaceView surface_view = (SurfaceView) findViewById(R.id.video_view_id);
if you are fetch view by id from your layout then you have to remove some line from code. which are:
surface_view = new SurfaceView(getApplicationContext());
addContentView(surface_view, new LayoutParams(50, 50));
Hope it will help you...
It is definitely possible but you might need to present a little more information. If you want some simple animation to run next to the textview then you don't even need a surfaceview. Just create an imageview and run an animation on it (here is a tutorial I created for the very topic)
TextView and its kin DO NOT derive from Surfaceview they derive from the View class. Once again if you want to perform simple animations I don't think you will need a surfaceview. If you want to do more dynamic complex things then there is also a tutorial on my development blog on how to utilize a SurfaceView for a game. If that is more your flavor then you can create a custom surface view and then just tie it into your layout with the size dimensions you want.

How to add a touch listener to a surface view?

I am new to Android, so please excuse if it is asked before!
I am playing with some camera code (found online) and I want to show/hide some buttons on screen. When the user touches the screen, I want it to capture the image.
My setup:
1.
Main Activity:
public class CameraDemo extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_inuse);
preview = new Preview(this);
((FrameLayout) findViewById(R.id.preview)).addView(preview);
... ...
// rest of the code that captures the image when a button is pressed.
// the button is defined in main.xml with button id ButtonClicked
}
2.
The preview class looks like this:
class Preview extends SurfaceView implements SurfaceHolder.Callback {
SurfaceHolder mHolder;
public Camera camera;
Preview(Context context) {
super(context);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
My question is,
How can I add touch functionality so that the user can touch the preview (say for a second, or just touch quickly) and something happens ? (Say image is saved)
And a button will appear on the surface say a "Next" button, for example?
#Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
in your preview class , the MotionEvent object will tell you what kind of touch it is (and position etc etc) and let you do whatever you want to do.

subclassing SurfaceView and overriding onDraw() to change SurfaceView parameters to generate preview of desired size

I have subclassed the SurfaceView and instantiating it in onCreate of the Activity. The preview is generated but the control never enters onDraw() which is overriden in the subclass of SurfaceView. Why is that?
class ActivityClass extends Activity{
onCreate(){
mPreview = new Preview(this);
setContentView(mPreview);
}
public void startPreview(){
rec = new MediaRecorder();
rec.setVideoSource();.......
rec.setPreviewDisplay(mPreview.getSurfaceHolder.getSurface());
}
}
class Preview extends SurfaceView implements SurfaceHolder.Callback{
SurfaceHolder mHolder;
public Preview(Context context){
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
bringToFront();//this is not
invalidate();//making a difference
}
SurfaceHolder getSurfaceHolder(){
return mHolder;
}
//Surface callback methods implemented here
}
Before drawing the preview on the Surface, shouldn't the control be given to the onDraw callback if it is implemented?
Because onDraw callback says to the Android framework 'you don't draw the view. I will draw it since I have been implemented'. Am I right?
Why then, is the control failing to enter onDraw()? Please help.
You simply have to add
setWillNotDraw(false)
To the constructor.
And its done..:)
public class SelectedRect extends View {
public SelectedRect(Context context) {
super(context);
bringToFront();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawLine(canvas);
invalidate();
this.bringToFront();
}
}
And in activity class :
View rect = new SelectedRect(this);
rect.bringToFront();
this.addView(rect, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
Something fishy is going on. It seems that you're trying to set the SurfaceView as a preview display. In that case, the Activity should implement SurfaceHolder.Callback (not the SurfaceView). This is so that the Activity can know when the SurfaceView has been created and is ready for drawing. Furthermore, it shouldn't even be necessary to extend SurfaceView: you should be able to user SurfaceView itself.
Assuming I misunderstood and you really want to extend surfaceview for some reason...
I don't see where you overrode onDraw in your Preview class. Did you not include this code?
When you say that the onDraw callback tells android 'you don't draw the view. I will draw it since I have been implemented', I disagree. onDraw is a function where a View draws stuff that all views have, such as the background. SurfaceView extends view. When you extend SurfaceView, you can override onDraw to tell android to draw stuff in addition to what the original onDraw in the View draws. In other words, Android always does all the drawing; overriding onDraw just tells it to draw a few more things when it's the right time to draw.

Categories

Resources