shrinking surfaceview to be in a box - java

I would like to change the current SurfaceView in my app from
to
Is there a way to do this without using main.xml at all?
I'm trying to code the GUI in run-time. I can achieve the current SurfaceView (top picture) by overriding onMeasure() and using setMeasuredDimension(), but I would like to achieve the bottom picture. The green area is the rest of the screen.
EDIT:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
this.setMeasuredDimension(500, 300);
param.gravity = Gravity.CENTER_VERTICAL;
}

Have you tried using the android:layout_gravity-attribute to center your View in the Layout?
The corresponding class would be FrameLayout.LayoutParams, possible gravity's are listed here. The code could then look something like this:
FrameLayout f = new FrameLayout(this);
ImageView test = new ImageView(this);
f.addView(test, new FrameLayout.LayoutParams(500, 300, Gravity.CENTER));

Related

onDraw not called in a custom view added to overlay with windows manager

I'm tearing my hair out over why my view only draws the first time. I've created a custom view that draws a bitmap for me. It's onDraw looks like this:
protected void onDraw(Canvas canvas) {
Paint p = new Paint();
canvas.drawBitmap(mBitmap, 0, 0, p);
Log.e(TAG, "CALLED");
}
Then in my main activity I set it up like this:
mDView = new drawableView(this, null);
mDView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
mDView.setOnClickListener(this);
mDView.setClickable(false);
mDView.setFocusable(false);
mDView.setWillNotDraw(false);
int id = 201;
mDView.setId(id);
wm.addView(mDView, topLeftParams);
wm is my windows manager
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Then finally I have a call back function that gets called in my main activity:
#Override
public void onFillEvent()
{
Log.e(TAG, "onFillMain");
mDView.setBitmap(mDepth.mFrameBuffer);
mDepth.fillDepthBuffer();
int id = 201;
getParent().findViewById(id).invalidate();
mDView.invalidate();
mDView.postInvalidate();
}
I've tried all three methods to invalidate the view in the windows manager. But what happens is the first bitmap it drew stays on the screen. I never see onDraw log "CALLED" after the first time. I do see my call back getting called all the time and logging onFillMain.
I later tried adding an onLayout method to my custom view but that doesn't call and log either. I'm pretty stuck what am I missing?
In order to trigger a change in the overlay, you have to call
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
wm.updateViewLayout(mDView, topLeftParams);

How to draw a view on top of everything?

I want to make an app that can create notification on the screen on top of anything that is currently being displayed. Something like the Go SMS message popup or something like the ChatHead in the following picture:
It would be even better if it is possible to draw it dynamically including touch events.What is the conventional or standard way to do this?
Example:
Like an Icon that can be clicked or dragged no matter whether you are on home screen or app drawer or other apps.Pay attention to the circular icons near the edges of the screen in the picture posted. You can drag them anywhere in any app.
What you are looking for is System Alert Window.
There's a library called StandOut! which will assist you in creating such apps.
Here is how things like Toast and dialog windows work:
In the case where just adding or bringing to front does not work, say when you are having a service add its own view to another client activity or application (FaceUnlock does this), or you cannot depend on hierarchies, you need to use the window manager and a window token to do the trick. You can then create layouts and take advantage of animations and hardware acceleration as before.
WindowManager windowManager = (WindowManager) getBaseContext().getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.FIRST_SUB_WINDOW);
layoutParams.width = 300;
layoutParams.height = 300;
layoutParams.format = PixelFormat.RGBA_8888;
layoutParams.flags =
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
layoutParams.token = getWindow().getDecorView().getRootView().getWindowToken();
//Feel free to inflate here
mTestView = new View(this);
mTestView.setBackgroundColor(Color.RED);
//Must wire up back button, otherwise it's not sent to our activity
mTestView.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackPressed();
}
return true;
}
});
windowManager.addView(mTestView, layoutParams);
Then be sure to remove the view onDestroy (or onPause) or you will crash
if (mTestView != null) {
WindowManager windowManager = (WindowManager) getBaseContext().getSystemService(Context.WINDOW_SERVICE);
if (mTestView.isShown()) {
windowManager.removeViewImmediate(mTestView);
}
}
You don't need a new activity to do this. All you need to do is to add another view into your existing activity and bring it to the front, and draw/write the things that you want into that view.
If you want to do special things with this extra view, you could create your own view class
class DrawOnTop extends View {
public DrawOnTop(Context activity) {
super(activity);
}
#Override
protected void onDraw(Canvas canvas) {
// put your drawing commands here
}
}
and then you do something like
DrawOnTop mDraw = new DrawOnTop(this);
addContentView(mDraw, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
mDraw.bringToFront();
Then to force it to draw, you need to use mDraw.invalidate();
You could have the parent of your whole layout as RelativeLayout. The first child being the "root" of your main layout. Anything after that can be considered an overlay which is placeable to your whims.
Example:
<RelativeLayout>
<LinearLayout>
... Main Layout here ...
</LinearLayout>
<TextView left="20dip" top="20dip" text="Overlay" alpha="0.7" />
</RelativeLayout>
The best way is to start a service with your application.
Create an ImageView.
Set the LayoutParams of the Image View.
Add the view along with the params to the window manager when the service is created.
ALL SET
Your Image sticks to your window (At any screen over all apps), till you application is closed.
You can even add onclicklisteners and ontouchlisteners to the imageview.
Eg. OnClick listeners to perform some actions and Ontouchlisteners move the image along the screen.

Problems drawing text onto an ImageView using a Canvas

I'm trying to implement a footer for my ListView which will act as a menu-type frame with five elements. I want the elements to be able to (dynamically, based on user input) display either images or text (or possibly both, but I'm not there yet). Eventually it will be more interactive but for now I was trying to implement it so that the ImageView (which by default displays an image) would erase the image and display text instead.
I thought the best way to implement this was to draw text on a canvas and use the android.view.View.draw(canvas c) method to draw it onto the ImageView. However, I'm having trouble doing this. Specifically, I can modify the view in almost any way (set the background color, change the drawable, etc etc) and it all works fine, and the code to draw the canvas compiles properly, but it doesn't do anything at runtime. The view remains completely unchanged.
(Note: I've tried to eliminate any stupid mistakes through code (i.e. made sure text wasn't transparent/same color as bg, made sure text was drawn inside the area of the view, etc) but I am not 100% it's error free.)
I tried both drawing to the view passed into the onClick function and drawing to a new ImageView constructed from the passed view - neither works.
Does anyone have any suggestions?
Code follows:
login_button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
Bitmap img = Bitmap.createBitmap( 60, 60, Config.ARGB_8888);
Canvas c = new Canvas();
c.setBitmap(img);
Paint myPaint = new Paint();
myPaint.setTypeface(mFace);
myPaint.setColor(android.R.color.black);
myPaint.setTextSize(2);
myPaint.setTextAlign(Paint.Align.LEFT);
String content = "testing";
c.drawText(content, 0,0, myPaint);
view.draw(c);//does nothing
ImageView view2 = (ImageView) view;
view2.setBackgroundColor(android.R.color.white); //this works perfectly
view2.draw(c);//does nothing
Toast.makeText(MainListView.this, ""+c.getHeight(), Toast.LENGTH_SHORT).show(); //making sure c has height - this returns 60 as expected
Toast.makeText(MainListView.this, "end of method", Toast.LENGTH_SHORT).show();
}
});
View.draw(Canvas) draws the View onto the Canvas, not vice versa like you seem to expect.
If you want to do it along the lines that you already are, you need to extend an existing View class, likely TextView or ImageView, and override onDraw(), as explained in the Custom Components Dev Guide.
I think what I would do is use something like a FrameLayout and set it to contain either the appropriate TextView or ImageView as necessary. That seems cleaner than manually rendering text in an ImageView.
You could create the Canvas from the Bitmap, and set the Bitmap as the Image for your ImageView.
Bitmap img = Bitmap.createBitmap( 60, 60, Config.ARGB_8888);
Canvas c = new Canvas(img);
Paint myPaint = new Paint();
myPaint.setTypeface(mFace);
myPaint.setColor(android.R.color.black);
myPaint.setTextSize(2);
myPaint.setTextAlign(Paint.Align.LEFT);
String content = "testing";
c.drawText(content, 0,0, myPaint);
ImageView view2 = (ImageView) view;
view2.setImageBitmap(img);
Toast.makeText(MainListView.this, ""+c.getHeight(), Toast.LENGTH_SHORT).show(); //making sure c has height - this returns 60 as expected
Toast.makeText(MainListView.this, "end of method", Toast.LENGTH_SHORT).show();
Although, I believe the "right" way to do this is to use an extension of View and override the onDraw method to draw differently based on some local variables:
login_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);
myPaint = new Paint();
myPaint.setTypeface(mFace);
myPaint.setColor(android.R.color.black);
myPaint.setTextSize(2);
myPaint.setTextAlign(Paint.Align.LEFT);
}
#Override
protected void onDraw(Canvas canvas)
{
if(mContextVariable)
{
//draw something
}
else
{
//draw something else
}
canvas.drawText("testing", 0,0, myPaint);
}
}

Why does LinearLayout child getWidth method return 0?

I have a LinearLayout, and this LinearLayout will hold dynamically placed views. I need to find out what the width of the children of LinearLayout, however this has to be done in onCreate method. From researching I've found out that you can't use getWidth from this method. So instead I'm using onWindowFocusChanged, which works for the parent LinearLayout (returning me the actual size), but it doesn't work with its children.
Another thing I noticed is that when the screen is fading away and the screen is locked, I can see at the logs the actual width of the children being returned (I think the activity is being paused).
I'm really stuck and this is needed because I need to dynamically place those views depending on the children width.
You might be able to get with the below. But as others pointed out, this probably isn't a great idea.
LinearLayout.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
LinearLayout.getMeasuredWidth();
inside the onCreate , views still can't know the state of the nearby views and the children ,etc... so only after all is prepared and the layout process is done , you can get the size of views .
here's a quick code for getting the size of the view just before it's being drawn:
private static void runJustBeforeBeingDrawn(final View view, final Runnable runnable)
{
final ViewTreeObserver vto = view.getViewTreeObserver();
final OnPreDrawListener preDrawListener = new OnPreDrawListener()
{
#Override
public boolean onPreDraw()
{
Log.d(App.APPLICATION_TAG, CLASS_TAG + "onpredraw");
runnable.run();
final ViewTreeObserver vto = view.getViewTreeObserver();
vto.removeOnPreDrawListener(this);
return true;
}
};
vto.addOnPreDrawListener(preDrawListener);
}
alternatively , you can use addOnGlobalLayoutListener instead of addOnPreDrawListener if you wish.
example of usage :
runJustBeforeBeingDrawn(view,new Runnable()
{
#Override
public void run()
{
int width=view.getWidth();
int height=view.getHeight();
}
});
another approach is to use onWindowFocusChanged (and check that hasFocus==true) , but that's not always the best way ( only use for simple views-creation, not for dynamic creations)
EDIT: Alternative to runJustBeforeBeingDrawn: https://stackoverflow.com/a/28136027/878126
https://stackoverflow.com/a/3594216/1397218
So you should somehow change your logic.

Transparent View with Android

I try to have a bitmap moving over my android application. I m be able to have my bitmap behind my text view, but not over them.
public void onCreate(Bundle savedInstanceState)
...
// ll is a FrameLayout
ll.addView(text1);
ll.addView(text2);
ll.addView(new Panel(this),200,400);
my Panel class is defined like this :
class Panel extends SurfaceView
......
#Override
public void onDraw(Canvas canvas) {
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
Bitmap bitmap;
GraphicObject.Coordinates coords;
for (GraphicObject graphic : _graphics) {
bitmap = graphic.getGraphic();
coords = graphic.getCoordinates();
canvas.drawBitmap(bitmap, coords.getX(), coords.getY(), null);
}
}
Can you help me ? How Can i Draw a transparent bitmap over my views of my application?
I never tried myself, but what about using this?
setForeground(Drawable drawable):
Supply a Drawable that is to be
rendered on top of all of the child views in the frame layout.
The drawable should be transparent: https://developer.android.com/reference/android/graphics/drawable/ColorDrawable.html
and the color might be something like #00XXXXXX as the 2 first digits are the alpha channel.

Categories