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).
Related
I'm having a requirement of draw a border around a parent layout in Xamarin.Android it can be any layout like FrameLayout, LinearLayout etc.
I have achieved this by using GradientDrawable - Which is just like setting a background for the layout with a shape.
So my requirement will be achieved
Query
When setting corner radius for the border, it is not clipping the children. How to clip the children or any other way alternative to do the both? Kindly share your suggestion on this.?
Note: I have tried with ClipChildren, ClipToPadding for the layout.
PS: Above images are mentioned for illustration purpose, they are not the exact output.
TIA.
You can clip the view using canvas. Use ClipPath(path) method of Canvas to clip the required area.
Syntax:
Path path = new Path();
path.AddCircle(200,200,100,Direction.CW);
canvas.ClipPath(path);
You can make use of ViewOutlineProvider API. As an example usage see ClippingBasic project.
Having defined outline provider class as such:
private class OvalOutlineProvider extends ViewOutlineProvider {
#Override
public void getOutline(View view, Outline outline) {
outline.setOval(0, 0, view.getWidth(), view.getHeight());
}
}
Then apply view outline to parent:
View parent = findViewById(R.id.parent);
parent.setOutlineProvider(new OvalOutlineProvider());
parent.setClipToOutline(true);
ViewOutlineProvider is accessible starting from API 21. Not sure, whether the solution is applicable for Xamarin (hope it does).
Setting ClipToOutline = true; for the parent, resolves the issue.
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.
I am transforming child views in my viewgroup when I'm swiping through the viewgroup (kind of a cover-flow effect). I am using matrix.setPolyToPoly for transformation. The views have borders which need antialiasing severely.
So far I've tried to use
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG));
in my children's onDraw, but it doesn't seem to change anything. Also, I'm aware of BitmapDrawable.setAntiAlias(true), but my children are not drawables, but full-blown viewgroups with views inside, so I cannot use that.
Override
protected void dispatchDraw(Canvas canvas)
in your custom layout and set filter there.
canvas.setDrawFilter(new PaintFlagsDrawFilter(1, Paint.ANTI_ALIAS_FLAG));
super.dispatchDraw(canvas);
I encountered a similar issue in my cover flow inspired Gallery. This solved my issue.
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.
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.