I have a Framelayout, where the first element is an ImageView which height and width is match parent and let the id is A. Second element is also an ImageView which height and width also match parent and let the id is B. Third element is a View which height and width is 100 dp and can be move to the whole screen and let the id is C. I am using transparent color in background C, so inside C we should see B, because B is above A. But I want to show A in inside C , how can I do that?
If I understand your question correctly, you basically want to have the intersection of View C and View B transparent to see View A which is behind both of them.
In that case it might be enough to get visible rectangle of view C:
Rect rect = new Rect();
viewC.getGlobalVisibleRect(rect);
And then you can draw this rectangle as transparent mask on view B, which will therefore allow you to see View A that is behind view B. You can achieve it by overriding onDraw method of view B.
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas)
canvas.drawRect(rect, paint);
}
This will achieve something similar to this:
You should also not forget to disable HW acceleration for view on which you are drawing (View B in this case) and also tell the view that you are going to draw to it manually:
setWillNotDraw(false);
setLayerType(LAYER_TYPE_HARDWARE, null)
Further explanation and example can be found here:
Android canvas: draw transparent circle on image
You can set visibility of B to invisible or gone, if you don't want to show B. Or you can replace A with B. As frame layout work like stack first thing you put goes to the bottom. so you put in this format B->A->->C
use relative layout to wrap your framelayout then you can use layout above and then work with visibility of views
This will help.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/a"
android:src="#drawable/ic_networking"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="#+id/b"
android:visibility="gone"
android:src="#drawable/dailymetricsin"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:background="#90606060"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
You can hide and show the ImageView based on the which one should show in the background either A (or) B.
Related
I have a custom view to display a simple piechart.
My intention is to take some values like size,background color etc thru Layout xml file.
I derive the radius of the circle, strokewidth etc as a factor of the height of the view(width is equal to width of the parent/screen) and all dimensions are based on this radius.
Here is my layout xml for the fragment
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/bluegrey200"
tools:context="ash.dbtest.GraphPieChartFragment">
<ash.dbtest.GraphPieChartView
android:layout_width="match_parent"
android:id="#+id/pieChart1"
custom:backgroundColor="#color/bluegrey800"
custom:labelColor="#color/white"
android:layout_height="800px"
/>
This appears perfectly fine now.
See the image:
The black rectangle is the area used in the overridden onDraw method. Note the blue diagonal line showing the bounds of the rectangle.
I know the height is mentioned in pixels and it must be in dp; but the values are now for debugging purpose.
I changed my layout xml file to below to add a banner above the Custom view in another linear layout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/bluegrey200"
tools:context="ash.dbtest.GraphPieChartFragment">
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:text="TestBanner"
android:textSize="20sp"
android:layout_height="wrap_content" />
</LinearLayout>
<ash.dbtest.GraphPieChartView
android:layout_width="match_parent"
android:id="#+id/pieChart1"
custom:backgroundColor="#color/bluegrey800"
custom:labelColor="#color/white"
android:layout_height="800px"
/>
See the screenshot now, it goes weird.
See image here:
Now my customview moves to the bottom, but is getting truncated. The onDraw method is getting the right dimensions and the circle is getting drawn correctly. But somehow the View is getting truncated. In the screenshot below, note that the black rectangle is incomplete and the blue diagonal line is getting truncated.
What could be the issue ?
I am a beginner around android and hope that I have provided all required information. I did not post the code because its just basic draws on canvas.
Thank you very much for your time on this.
Code on the GraphPieCharView.onDraw
#Override
public void onDraw(Canvas canvas) {
Log.d("onDraw","onDraw");
Log.d("onDraw1",Float.toString(this.getLeft()));
Log.d("onDraw2",Float.toString(this.getTop()));
Log.d("onDraw3",Float.toString(this.getRight()));
Log.d("onDraw4",Float.toString(this.getBottom()));
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setStrokeWidth(20);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(BACKGROUND_COLOR);
canvas.drawRect(this.getLeft(),this.getTop(),this.getRight(),this.getBottom(),paint);
because your GraphPieChartView is below TextView
Figured it out.
I was drawing the rectangle using the below code
canvas.drawRect(this.getLeft(),this.getTop(),this.getRight(),this.getBottom(),paint);
Lets say the page is 1500px high and 1000px wide.
Here, when the customview is the only view on the page, below are the results of the getters.
left - 0
top - 0
right - 1000
bottom - 800
I drew the rectangle in these bounds, and all the calculation based on these bounds; it worked fine.
Now, when the custom view is the second view when listed vertically, with the top TextView taking say 50px,
left - 0
top - 50
right - 1000
bottom - 850
But these values are relative to the whole screen (1000*1500).
But inside my custom view, the canvas I have is 1000*800, starting from 0,0 and ending at 1000,800 diagonally.
But I was drawing on the canvas as if it starts from 0,50 and ending at 1000,850.
Adjusted the calculation inside the onDraw method to always start from 0,0 and it solved the issue.
Thanks for all the responses.
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 nested inside of a ScrollView. The idea is that the custom view can be longer than the height of the screen, so when you swipe through the ScrollView you can see all of its contents.
In order to do this I adjust the clip of the custom view's canvas like this:
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.clipRect(mCanvasArea, Region.Op.REPLACE);
}
Where mCanvasArea is a pre-generated RectF which represents the entire area the canvas can draw. I logged it's value # 10308.
However when the app runs, the custom view is unscrollable, it acts as if the visible content represents all of the content in the canvas, but I can see more peeking up from the bottom of the screen.
Here is my XML declaration for the view:
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/activity_toolbar"
android:fillViewport="true">
<com.myapp.CustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</ScrollView>
(I had to add fillViewport in order to get the content to show up in the first place)
Is there anything else that needs to be done in order yo make the view scroll?
You will need to specify the height of the custom view, not the canvas. The canvas passed to onDraw reflects the width and height of the view.
Setting the view to wrap_content doesn't mean it will grow whenever you draw outside of its bounds. It will only "wrap" the child views, not the canvas.
To set your view's height programmatically:
getLayoutParams().height = 500;
invalidate();
I'm not sure what you are going for with this exactly so I can't get too much more specific about where you should set the height, but I'd recommend not changing your view's dimensions in onDraw because when you invalidate it will cause another draw and you'll need some funky logic to handle this recursion.
Instead you could determine the height you need when the view is constructed, and then override onMeasure with something like this:
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, calculatedHeight);
}
This would force your custom view into the calculated height.
Currently, I have a custom view BarChart. I wish to have some red shadowing effect on it. I'm using nine patch image technique to achieve so.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:minHeight="240dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/card_background_red"
android:orientation="vertical"
android:padding="0dp" >
<org.yccheok.jstock.gui.charting.BarChart
android:id="#+id/bar_chart"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
In my custom view, there is line of code, where I will draw string at the end-y of the view.
// Drawing string at end-y of BarChart custom view.
canvas.drawText("2007", x0, getHeight(), textPaint);
canvas.drawText("2008", x1, getHeight(), textPaint);
I avoid my custom view from "touching" any of the red shadow, I define my content area of 9-patch, so that it doesn't touch the red shadow.
As you can see, the content area are pretty much stay away from red shadow.
I thought my drawn text will never touch the red shadow area, as I restrict my content area (entire custom view?) stay away from red shadow area. However, it doesn't work.
Am I having wrong expectation on the content area of 9 patch image? I thought Linear Layout's "content" is my custom view BarChart. Hence, BarChart shouldn't be touching the red shadow as specific in 9 patch image. (http://www.shubhayu.com/android/9-patch-image-designers-vs-developers)
Remove android:padding="0dp" from LinearLayout. It overrides padding from 9-patch.
I have a custom view that is sort of a vertical progress bar. It's just a custom view, drawing onto the canvas to fill from bottom to top with the percent complete. In my xml, I have text above, and text below the custom control (there are two of these, one on the left, one on the right, here's the right):
<RelativeLayout android:layout_width="150dp"
android:layout_height="fill_parent" android:layout_alignParentRight="true">
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="#+id/bar_right_text" android:text="Right"
android:layout_alignParentTop="true" android:gravity="center_horizontal" />
<com.myApp.VBarView android:id="#+id/right_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/bar_right_text"/>
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="#+id/bar_right_time_text" android:text="Time Remaining" android:layout_below="#id/right_bar" android:gravity="center_horizontal" />
</RelativeLayout>
In my custom view, I check the height in every way I can think of, but I always get a height that goes all the way to the bottom of the screen
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// h here is 489
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
int myHt = getHeight();
int myMeasHt = getMeasuredHeight();
Rect canvasRct = canvas.getClipBounds();
// all of these (myHt, myMeasHt, and canvasRct.getHeight()) are all 489
}
So far, I have tried reversing the views in the layout, so the top text is first (top aligned), the bottom text is second (bottom aligned), and the custom control is last (layout_above the bottom text), with both match_parent and wrap_content, to no avail. I tried changing to a linear layout, still with no better result.
In the case shown in code, the top text is displayed, but the bottom text is gone. When I changed the order so the custom view was layout_above the bottom text, it just moved the drawing area up so the bottom text was visible, but covered the top text. Note that when I say the bottom text is gone, I mean gone, not just covered up. My final test was to hardcode the layout_height to "350dp" in the layout.
In all cases, I always get a height of 489 on this particular device, even with the height hard-coded. I can not figure out what I need to do to get the middle part of the screen as something I can draw on and leave the rest alone. Are custom views assumed to be the last thing in a layout? The only way I can get this to work is to change the order so the custom view is last in the layout so that the bottom of the custom area is on top of the bottom text, the bottom text is still displayed, and then manually add about 150 to the top (i.e. don't write into zero on the canvas provided to the onDraw()) so it doesn't cover the top text. Fortunately, the graphic I'm drawing in is semi-transparent, so I can see whether the text is covered or just gone.
Does anyone have more info on how this is supposed to be working? Did I manage to make the explanation of what I did more confusing than the actual problem?
Thanks,
gb
Someone suggested offline that instead of just placing the custom field "above" or "below" one of the other fields, do both. Keep it as the last item in the XML, and set android:layout_above and android:layout_below. I did that, and now my heights come in correctly.