I'm using OpenGL to dynamically render images on a GLSurfaceView within android.
The application runs perfectly fine for (static) XML-based layout with multiple instances of a custom GLSurfaceView. (top left- and top right on the image)
If these instances get dynamically interchanged by the visibility value, the last visible OpenGL-image is still on top of the new one. (bottom left- and bottom right on the image)
top left picture: 4 instances, normal size
top right picture: 4 instances, big size
bottom left picture: 1 instance, normal size (top left picture as unwanted overlay)
bottom right picture: 1 instance, big size (top left picture as unwanted overlay)
What I tried so far:
did not remove the unwanted instances:
hide unused images by android::visibility="gone" (does not work smooth)
move the views out of the visible area and resize them to 0 by 0
use plain colors instead of dynamic images to simplify the output
force a redraw of the view by invalidating it (I actually tried almost every function a view offers)
clear various buffers in the onDraw()-function (I actually tried almost every function the GLSurfaceView offers)
force a onPause()-event to stop the renderer
use the ViewPager to switch between the views
removed the unwanted instances successfully:
restart OpenGL by reentering the app (can't be used like this)
recursively hide all other GLSurfaceViews by android::visibility="gone" (bugged the engine, so it stopped working)
The unwanted images does not change with layout reflows like a visibility change of a view.
They are only visible if a GLSurfaceView is over another GLSurfaceView (hidden by android::visibility="gone").
There is no problem if a ImageView is used instead.
The first created instance do not have this problem, because it is on top (or bottom?) of the child-stack and is on top of its siblings.
I guess android supports only one OpenGL based view which is used by all instances of GLSurfaceView.
All instances seem to share some preferences (especially the visibility), so it can't just turned off or moved out.
GLSurfaceView-class:
public class Panel extends GLSurfaceView implements Renderer {
private static native void nativeRender();
public Panel(Context context) {
super(context);
this.setRenderer(this);
this.setRenderMode(RENDERMODE_WHEN_DIRTY);
}
public void onDrawFrame(GL10 gl) {
nativeRender();
}
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
super.surfaceDestroyed(holder);
}
public void callback() {
this.requestRender();
}
}
So is it possible to use multiple OpenGL-views within (especially on top) of each other? is there a better way to interchange them without the use of the visibility value?
I was having same problem and couldn't solved the problem as i finally understand that one GLSurfaceView will be one top if we make another GLSurfaceView's visibility GONE & it won't be coming back on top of screen.
But i solved the problem with a trick. Instead of hiding the view, i changed it's width and height to 1 px, it's makes the view invisible to user. And when i need to show it , i changed it width & height via LayoutParams. And it partially solved my problem. I am showing you my code
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/smallVideoRenderLayoutIncoming"
android:layout_width="1dp"
android:layout_height="1dp"
android:background="#color/transparent"
android:orientation="vertical"/>
<LinearLayout
android:id="#+id/largeVideoRenderLayoutIncoming"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ConstantFunctions.dpToPx(120),ConstantFunctions.dpToPx(170));
smallVideoRenderLayoutIncoming.setLayoutParams(layoutParams);
When i need to show it, i changed it's size as i needed.
Related
I am writing a game in which i need to check collisions between two views. when i use the view.getHitRect(outputRect) method from some reason the bottom padding of the view (all the other paddings are set to 0) is added to the top property of the view's hit rectangle. I've tried to fix this by overriding the getHitRect method:
public abstract class GameView extends ImageView {
#Override
public void getHitRect(Rect outRect) {
super.getHitRect(outRect);
outRect.top+=getPaddingBottom();
}
This got me a better result, but its still inaccurate, and the bigger the padding gets the less accurate the rectangle becomes, and the collision always occur too low. Before using paddings I was trying to do it without it, which gave me accurate hitRect but i got a different bug. Thanks in advance
Solved it after some trial and error. Apparently the padding was added to the rectangle, but it was divided equally between the rect.top and rect.bottom, so the solution was:
#Override
public void getHitRect(Rect outRect) {
super.getHitRect(outRect);
outRect.top+=getPaddingBottom()/2;
outRect.bottom-=getPaddingBottom()/2;
}
If one of you Android experts care to explain why I would be grateful, since I don't understand how it works and I just can't see the logic in it.
I am implementing stuff like YouTube App which you can drag the video window to the lower right corner.
I am able to achieve the same effect using setLayoutParam(), but it turns out not as fast as I expected (as smooth as YouTube).
So I use setScaleX and setScaleY instead. It's fast and the behavior is similar to YouTube app. But the scale seems not applied to the child views.
So, what can I do to efficiently scale a ViewGroup and it's child views. Thanks.
layout.xml:
<ScalableRelativeLayout android:id="#+id/parent" >
<VideoView android:id="#+id/video"/>
</ScalableRelativeLayout>
When the parent get scaled, the video seems not scaled and only shows part of it. I guess the parent scale didn't pass to its children, so I override below method.
Override method:
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
canvas.scale(mScale, mScale);
super.dispatchDraw(canvas);
canvas.restore();
}
ScalableRelativeLayout extends RelativeLayout and override above method. Now the video scale inside parent, only occupy upper-left area.
It seems the video content will not affected by the view.
I have a custom FrameLayout class which does some custom drawing on the OnSizeChanged event. It's done there and not in the OnDraw event to avoid reentrancy and therefore performance issues. This works fine in a single activity application but fails in a TabActivity. The activity in the current tab renders fine but activities in non-active tabs are not being rendered. Here you can download an example project reproducing this. The project is HelloTabWidget but uses HelloAndroid project as well.
Found that onWindowVisibilityChanged event might help but need to find adequate size to plot my control. In the code snippet below I'd need a way to find container's size at onWindowVisibilityChanged.
#Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
int width = this.getWidth();
int height = this.getHeight();
drawContent(getCtxt(), width, height);
}
The solution was using OnDraw event doing some refactoring to the component and using a boolean flag to determine when the canvas is dirty to avoid unneeded reentrancy. SetWillNotDraw had to be set to false as well.
I have a need to create a perfect square TableLayout. The table is a grid of equal sized objects. The problem here is that in landscape layout, the table should take up the maximum amount of space but nothing more. In other words, I need the width of the table equal to the maximum height allowable. An ad appears ~10 seconds or so after the activity starts so that also adds to the complexity.
Here is what I've tried so far to accomplish this:
I created a invisible view that was aligned horizontally center. I then aligned the right side of the table to this view. This works but for some devices, the screen ratio doesn't make this setup perfect. On devices like the droid, the bottom row is squinched in because the table width is smaller than the height.
I created an ImageView with adjustViewBounds set to true. I sourced it with a very large square image. I have it set to be above the adView and align top and align left. I then set the table layout to align to the bounds of that ImageView. This didn't work because it was a memory hog and the image bounds never fully adjusted when the ad popped up. The image source would go to a smaller scaled square but the right bound never adjusted to the new bounds.
I think this could be very easy if I made a custom class of the TableLayout and set the tablewidth = tableheight. I am struggling with this idea because I don't know where all I would need place the necessary logic. I suppose I would need to add it when the table gets initially drawn and again when the Table adjusts after the ad moves into place.
Can someone help with some sample code on the TableLayout class? Is there another way to do this?
Update 3/30 9:05PM PST
I've made some progress with a custom TableLayout class after looking through the suggestion from CommonsWare. I'm closer to achieving the solution using this class but have one left thing to solve. The new TableLayout doesn't adjust it's bounds so the width is still taking up additional space even though the contents are sized correctly. The width looks to be set when there isn't an ad and it never changes after that.
Here is my really simple extended TableLayout class. Note the onMeasure method where I set the width and height both equal to the height:
public class SquareTableLayout extends TableLayout {
public SquareTableLayout(Context context) {
super(context);
}
public SquareTableLayout (Context context, AttributeSet attrs) { super(context, attrs); }
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
}
}
Here is a screenshot of the problem. I added apurple background to the TableLayout to highlight the problem.
http://ribzy.com/images/tile_takedown_landscape.png
TableLayout cannot accomplish what you seek, for the reasons you have determined. There is no built-in layout that has the notion of tying width and height together. Most likely, you will need to create a custom layout manager from scratch, like this one.
I am a beginner android developer and I am trying to have a button display on top of the bitmaps I am outputting.
Here is what I have:
my activity sets this:
setContentView(new FrameView(this));
FrameView is a class that extends View:
public FrameView(Context context) {
super(context);
setFocusable(false);
Inside FrameView I have
#Override protected void onDraw(Canvas canvas){
...
canvas.drawBitmap(image1.getBitmap(), 0, 0, null);
...
}
main.xml is FrameLayout that I stuck a button on top of, that's it.
I guess my question is, how do I insert something into the main.xml as a "canvas" in order to paste my bitmaps to, but still have the button always on top regardless of how many bitmaps i draw?
Use a RelativeLayout. Put your "canvas" as the first child, sized and positioned as you see fit. Put your button as the second child, sized and positioned as you see fit. Your button will "float" over your "canvas", because later children of a RelativeLayout are higher on the Z axis.