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.
Related
I am trying to design an UI very similar to this. I have been able to design it almost similar to the image above, but am not getting a way to implement the slanting or sloping part.
1) Can any one give an example layout of how can I implement the slanting layout?
2) And how can I place the FAB right there over the slant portion?
Any help would be really appreciated.
You can create a custom view with Slant top using Canvas and then place it over your TextView, to achieve this look and feel.
Code snippet for slant top custom view:
public class SlantView extends View {
private Context mContext;
Paint paint ;
Path path;
public SlantView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
mContext = ctx;
setWillNotDraw(false);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
#Override
protected void onDraw(Canvas canvas) {
int w = getWidth(), h = getHeight();
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setAntiAlias(true);
path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
path.moveTo(0,0);
path.lineTo(0,h);
path.lineTo(w,h);
path.close();
canvas.drawPath(path, paint);
}
}
Code snippet for how to use it with TextView
<com.pix.app.views.SlantView
android:layout_width="match_parent"
android:layout_height="30dp"
android:id="#+id/slant_view"
/>
<TextView/>
Other way to achieve Slant View is this:
<FrameLayout android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="#color/colorAccent"
xmlns:android="http://schemas.android.com/apk/res/android" >
<ImageView
android:layout_width="match_parent"
android:layout_height="280dp"
android:src="#color/colorPrimary"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:rotation="-70"
android:layout_marginTop="100dp"
android:background="#color/colorAccent"></LinearLayout>
</FrameLayout>
This will give you following output:
1) Can any one give an example layout of how can I implement the slanting layout?
You cannot. Views are always rectangular. You may however make it look slanted, i.e. with background image.
2) And how can I place the FAB right there over the slant portion?
You cannot have slant. It's just bottom edge of the square bounding box. So you should be able to put it there w/o any problem.
Normally images are represented in rectangular form. You can use padding/margin to design UI according to your need. Obviously other than sloping part will be transparent image.
You need to have the root or at least the immediate parent layout as FrameLayout, then,
1) For the image part, you can have a normal ImageView to show the image. Below that you can have a LinearLayout (blank, with white background).
Now just tilt the blank LinearLayout to an angle probably 45 degrees to cut the background image in slant style. Here, just set the XML property of the blank LinearLayout,
android:rotation = "45"
2) For the FAB, just move it to the cutting point, gravity of the layout should be set to right according to your screenshot.
Hope this helps. Cheers!
You'll have to write a custom View to do it. There's no native control that can do this.
Canvas's provide support for clipping paths, so it's easy enough to clip the image provided you can draw the image. That being said, drawing large images in an OnDraw implementation is less than straightforward (memory management and correct scaling and caching behaviour isn't difficult, but it's less than trivial)
An easier way to do it would be to extend something like a FrameLayout or some kind of ViewGroup. If you override dispatchDraw, you can push a clip path onto the canvas, which will clip children. And then you can put other controls inside your custom control.
Something like this:
public class ClipFrameLayout extends FrameLayout {
.... constructors and stuff...
#Override
void dispatchDraw(Canvas canvas)
{
canvas.save();
canvas.clipPath(mCustomClipPath);
super.dispatchDraw(canvas);
canvas.restore();
}
}
I have a custom view which is a RelativeLayout which contains a ListView (both are set to match parent - width and height).
On top of the list I have a View as seen in the picture below:
I want that the only part that will be drawn is the rect of my View (marked with gray), while all the other portion of the view will be transparent.
is there a way I can do this?
I already tried to extend RelativeLayout and override its onDraw() method, but I didn't manage to draw only the specific region (marked in gray).
Eventually, I did it by extending RelativeLayout and override its draw() method.
#Override
protected void draw(Canvas canvas) {
canvas.clipRect(magnifiedRegion.getLeft(), magnifiedRegion.getTop(), magnifiedRegion.getRight(), magnifiedRegion.getBottom());
super.draw(canvas);
}
where magnifiedRegion is my View as it mentioned in the question above.
Note: you must set this.setWillNotDraw(false); in the constructor or else, draw() method won't be called by the framework (since our root view is a ViewGroup - it's an optimization Android framework does by default).
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.
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.
Is it possible to add TextView and ImageView on canvas?
Canvas does not inherit from ViewGroup, so it does not have the ability to add child views to it.
With Canvas, you use drawBitmap and drawText methods to draw images and text instead of adding child controls like TextView and ImageView.
It's a round about way, but this tutorial adds a textview to his canvas:
http://www.helloandroid.com/tutorials/how-draw-multiline-text-canvas-easily
If you need to freely position ImageViews and TextViews, you should use a RelativeLayout.
The RelativeLayout has advanced positioning features and allows overlapping.
- put your view (which is using canvas) inside the RelativeLayout,
public class YourComponent extends View{
#Override
protected void onDraw(Canvas canvas)
...
public void onDraw(){
....
....
ImageView yourImageView = .....
RelativeLayout.LayoutParams fParams = new RelativeLayout.LayoutParams(25,25);
fParams.leftMargin = 100; //x coordinate
fParams.topMargin = 25; /y coordinate
yourImageView.setLayoutParams(fParams);
((RelativeLayout) YourComponent.this.getParent()).addView(yourImageView);
}
}
above code : i created layout params which shows 25x25 dimensions for view. and after that , i used margins to set proper position on the parent layout. and set this LayoutParams to ImageView. and for last, i added this imageView to parent Layout.
But beware that during the onDraw() execution, calling operation on external view may stop onDraw(). so if you want to use this way be sure you already completed all onDraw operation.
I am not so sure why this happens. I did not try to observe too much on it yet.