I have a main activity class, I've also got a SurfaceView class that starts when my main activity starts.
I've got a seek bar in the main activity. I'd like to send whatever data that the seek bar produces to the SurfaceView to show it, every time it changes.
How can I do that?
Thanks.
Here is my SurfaceView class:
public class SurfaceViewGauge extends SurfaceView implements SurfaceHolder.Callback{
private MySurfaceThread thread;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public SurfaceViewGauge(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public SurfaceViewGauge(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public SurfaceViewGauge(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
private void init(){
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);
setFocusable(true); // make sure we get key events
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
}
catch (InterruptedException e) {
}
}
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
}
}
And Here is my Thread class:
public class MySurfaceThread extends Thread {
private SurfaceHolder myThreadSurfaceHolder;
private SurfaceViewGauge myThreadSurfaceView;
private boolean myThreadRun = false;
public MySurfaceThread(SurfaceHolder surfaceHolder, SurfaceViewGauge surfaceView) {
myThreadSurfaceHolder = surfaceHolder;
myThreadSurfaceView = surfaceView;
}
public void setRunning(boolean b) {
myThreadRun = b;
}
#Override
public void run() {
// TODO Auto-generated method stub
while(myThreadRun){
Canvas c = null;
try{
c = myThreadSurfaceHolder.lockCanvas(null);
synchronized (myThreadSurfaceHolder){
myThreadSurfaceView.onDraw(c);
}
sleep(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
myThreadSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
in your MainActivity declare a static variable which will hold seekbar value and in your surfaceview code with the help of handler just call that static variable
e.g.
MainClass.seekValue;
In your Code, add Handler..
public Handler mhandler;
public SurfaceViewGauge(Context context, Handler mhandler)
{
super(context);
this.mhandler = mhandler;
// TODO Auto-generated constructor stub
init();
}
In the above code, use the Handler object for sending the code.
Related
I'm using FrameLayout to but some views above other views
and I want to register onTouchListener on this layout
I made the activity implements OnTouchListener
but "onTouch" method doesn't called when i touch the screen !!
this is my code
public class Mapactivity extends Activity implements OnClickListener,
TranslationListner , OnTouchListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map_fragment);
FrameLayout mlayout;
mlayout = (FrameLayout) findViewById(R.id.map_root);
File Tfile = this.getFilesDir();
String Ttest = Tfile.getAbsolutePath();
StorageEntity entity = new StorageEntity("map", ".xml", null, "Shine"
+ File.separator + "Sites", false);
SiteMap map = null;
try {
map = MapParser.parseMap(entity, this);
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
boolean fm = map.equals(null);
MapView view = new MapView(this, map, 2);
view.registerTranslationListner(Mapactivity.this);
view.setBackgroundColor(Color.WHITE);
mlayout.addView(view);
AreaCentroid = map.getCenteroid(2);
for (Area area : map.getFloorMap(2).getAreas()) {
if (area.getAreaType() == Path.HALL) {
ImageView hIcon = new ImageView(this);
hIcon.setImageResource(R.drawable.hall);
hIcon.setPadding(area.polygon.centeroid().x,
area.polygon.centeroid().y, 0, 0);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
hIcon.setLayoutParams(lp);
icons.add(hIcon);
mlayout.addView(hIcon);
}
}
view.registerTranslationListner(Mapactivity.this);
mlayout.setOnTouchListener(Mapactivity.this);
}
I found the answer
the way to handle motion events is to make custom layout that extends framelayout
like that
public class MapLayout extends FrameLayout {
public MapLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public MapLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MapLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
}
and then override onInterceptTouchEvent which called on any touch event happens on any child view in this layout
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
mScaleDetector.onTouchEvent(ev);
mMoveDetector.onTouchEvent(ev);
for (View childView : childerns) {
}
return false;
}
Is there any way to get objects to foregorund in surfaceView.
for example:
canvas.drawBitmap(...);
canvas.drawText(...);
If I do that text appeared on bitmap. How can I reverse it without redrawing
Sorry for my English.
Canvas just encapsulates bitmap object and bitmap only saves colour of pixel at some position, it doesn't save separate layers. It's like to draw in MSPaint. So you can't change the Z-order of your primitives on canvas. However, why don't you just change the order of commands?
There is no method to bring elements front and back. You are trying to alter the Z-order of the elements here and this is not possible or there is no direct method in Android. All you can do is arrange them in the layout and enable and disable views so that it will give you the same effect.
You can use addView() or setVisibility(View.Visible) to bring bring elements back and front.
Please try to use bellow code.
//SurfaceView class
public class MainGamePanel extends SurfaceView implements
SurfaceHolder.Callback {
MainThread thread;
public MainGamePanel(Context context) {
super(context);
// TODO Auto-generated constructor stub
getHolder().addCallback(this);
setFocusable(true);
thread = new MainThread(getHolder(), this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
Log.e("N", "Changed");
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
Log.e("N", "Created");
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
Log.e("N", "Destroyed");
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (event.getY() > getHeight() - 50) {
thread.setRunning(false);
((Activity) getContext()).finish();
} else {
Log.d("N", "Coords: x=" + event.getX() + ",y=" + event.getY());
}
}
return super.onTouchEvent(event);
}
}
//MainThread class
public class MainThread extends Thread {
// flag to hold game state
private boolean running;
private SurfaceHolder surfaceHolder;
private MainGamePanel gamePanel;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
#Override
public void run() {
long tickCount = 0L;
Log.d("N", "Starting game loop");
while (running) {
tickCount++;
// update game state
// render state to the screen
}
Log.d("N", "Game loop executed " + tickCount + " times");
}
}
//Main Activity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MainGamePanel(this));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
i managed to animate a View on a Layout using ObjectAnimator.
i tried animating objects on canvas using the ObjectAnimator class but it didn't work.
is it even possible?
what i did is creating a class extending View, i defined the ObjectAnimator like i did on the Layout, then i drew it on the canvas and started the animation (objectanimator.start)
here is the code:
(the // lines are my Layout try witch worked)
public class MainActivity extends Activity {
SurfaceClass surface;
private ObjectAnimator anima;
//private Button but;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surface = new SurfaceClass(this);
surface.resume();
setContentView(surface);
//but = (Button)findViewById(R.id.button1);
//anima = ObjectAnimator.ofFloat(but, "y",400);
//anima.setDuration(5000);
//anima.setRepeatCount(100);
//anima.setRepeatMode(1);
//anima.start();
}
surface:
public class SurfaceClass extends SurfaceView implements Runnable{
SurfaceHolder sHolder;
Boolean isRunning;
Thread th;
Canvas c;
Obj object;
ObjectAnimator anima;
public SurfaceClass(Context context) {
super(context);
// TODO Auto-generated constructor stub
anima = ObjectAnimator.ofFloat(object, "y",1f);
anima.setDuration(3000);
anima.setRepeatCount(100);
anima.setRepeatMode(1);
//anima.start();
object = new Obj(context);
sHolder = getHolder();
isRunning = false;
}
#Override
public void run() {
// TODO Auto-generated method stub
while(isRunning){
if(!sHolder.getSurface().isValid())
continue;
c = sHolder.lockCanvas();
synchronized(sHolder){
doDraw(c);
}
sHolder.unlockCanvasAndPost(c);
}
}
private void doDraw(Canvas c) {
// TODO Auto-generated method stub
c.drawBitmap(object.pic, object.x, object.y, null);
anima.start();
}
public void resume() {
// TODO Auto-generated method stub
isRunning = true;
th = new Thread(this);
th.start();
}
}
object:
public class Obj extends View {
float x = 200,y=30;
Bitmap pic;
public Obj(Context context) {
super(context);
// TODO Auto-generated constructor stub
pic = BitmapFactory.decodeResource(getResources(), R.drawable.cat_trance);
}
public void setY(float f){
y=f;
}
public float getY(){
return y;
}
}
try this,
#Override
protected void onAttachedToWindow(){
anima.start();
}
and remove anima.start(); in doDraw method.
I want to add image to Surface view. So i used below code
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
Bitmap myicon;
Canvas canvas;
private Paint mBitmapPaint;
Paint p= new Paint();
#Override
protected void onDraw(Canvas canvas) {
Bitmap myicon=BitmapFactory.decodeResource(getResources(),R.drawable.icon);
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(myicon, 0,0, p);
// canvas.drawBitmap(myicon, 0,0, null);
// canvas.drawBitmap(myicon, 25,25, null);
}
public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
}
}
But it shows black screen. I didn't get what i did wrong in above code.
Please solve the problem
Thanks in advance.
Here is your solution Buddy, Also look at this link from where I got the solution
MainAct.java
public class MainAct extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mySurfaceView mySurfaceView = new mySurfaceView(getApplicationContext());
setContentView(mySurfaceView);
}
}
mySurfaceView.java
public class mySurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
private TutorialThread _thread;
public mySurfaceView(Context context) {
super(context);
getHolder().addCallback(this);
_thread = new TutorialThread(getHolder(), this);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Bitmap _scratch = BitmapFactory.decodeResource(getResources(),
R.drawable.icon);
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(_scratch, 10, 10, null);
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
public void surfaceCreated(SurfaceHolder arg0) {
_thread.setRunning(true);
_thread.start();
}
public void surfaceDestroyed(SurfaceHolder arg0) {
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
class TutorialThread extends Thread {
private SurfaceHolder _surfaceHolder;
private mySurfaceView _panel;
private boolean _run = false;
public TutorialThread(SurfaceHolder surfaceHolder, mySurfaceView panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
#Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.onDraw(c);
}
} finally {
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
EDIT :
droidnova website is not available anymore.I have found alternative website here which is having same source.
I hope it will be helpful !!
There are some changes to your class
package com.sample;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MSurface extends SurfaceView implements SurfaceHolder.Callback {
public MSurface(Context context) {
super(context);
getHolder().addCallback(this);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Bitmap icon = BitmapFactory.decodeResource(getResources(),R.drawable.icon);
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(icon, 10, 10, new Paint());
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Canvas canvas = null;
try {
canvas = holder.lockCanvas(null);
synchronized (holder) {
onDraw(canvas);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
}
But I am not sure you need SurfaceView, cause it used not to draw bitmap once, but to draw a lot of times after user interaction
If your view is not interactive, would be better if you extend View instead of SurfaceView
Cheers
I am learning how to code with Android but I am still confused bby the way it works, I am able to create simple draws like circles and stuff but now i want to paint the circle multiple times with a delay of 2 seconds.. I would appreciatge if you experts can help me improve my code and to put the stuff in the correct place
public class ColorChanges extends Activity {
DrawCircle dc;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawCircleToCanvas()
}
void drawCircleToCanvas()
{
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dc.postInvalidate();
}
};
Thread updateUI = new Thread()
{
public void run() {
dc = new DrawCircle(this); //this line does not work
dc.setBackgroundColor(Color.WHITE);
setContentView(dc);
handler.sendEmptyMessage(0);
}
};
updateUI.start();
}
}
public class DrawCircle extends View {
Paint p1 = new Paint();
Paint p2 = new Paint();
Paint p3 = new Paint();
Paint pAll[] = new Paint[3];
public DrawCircle(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public DrawCircle(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public DrawCircle(Context context) {
super(context);
p1.setStyle(Paint.Style.STROKE);
p1.setColor(Color.GREEN);
p1.setStyle(Paint.Style.FILL);
p2.setStyle(Paint.Style.STROKE);
p2.setColor(Color.BLUE);
p2.setStyle(Paint.Style.FILL);
p3.setStyle(Paint.Style.STROKE);
p3.setColor(Color.YELLOW);
p3.setStyle(Paint.Style.FILL);
pAll[1] = p1;
pAll[2] = p2;
pAll[3] = p3;
// TODO Auto-generated constructor stub
}
#Override
public void onDraw(Canvas canvas)
{
for (int i = 0; i < pAll.length;i++)
{
canvas.drawCircle(200, 200, 100, pAll[i]);
}
}
}
If you want to draw the same circle with its color changing over the time (each 2 seconds as you mentionned) you should use an Handler
in order to create a timer and to switch the paint at each time it is called.
Do not forget to call the invalidate function inside your custom view, as this function ask the system to redraw the screen.