Android Custom View inside Linear Layout with other views - android

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.

Related

Showing part of the ImageView which is cover by another ImageView

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.

9-patch drop shadow disappears when image nears the edge

I'm using 9-patch to produce drop shadow for a box. If the image width is at 280dp (20dp off the edge of the box), I get a good drop shadow (#315 degrees):
However, if I make the image touch the box edge, the shadow on the right edge almost disappears:
Here's my layout:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#drawable/dropshadow">
<ImageView
android:id="#+id/frontimage"
android:layout_width="match_parent"
android:layout_height="130dp"
android:layout_alignParentTop="true"
android:scaleType="center"
/>
...
</RelativeLayout>
Here's the 9-patch I'm using:
Does anyone know why this is happening?
Thanks!
Reduce your top and left black border to 1 px (the stretchable area).
Like so:
Optionally, you can also reduce the right and bottom black border by some pixels (to introduce some padding).
Like so:
Optionally, you can add some blank (transparent) space (let's say 4px per side) between the image (shadow included) and the black borders.
This will add some padding.
OR
You can add some padding to your RelativeLayout

Content area defined in 9 patch image doesn't work for custom view

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.

Animate ImageView width without scaling

I'm trying to animate an ImageView so it's slowly shown from left to right.
When I asked this before I was having trouble to explain what I wanted, so this time I created the desired effect using HTML / JS:
http://jsfiddle.net/E2uDE/
What would be the best way to get this effect in Android?
I tried changing the scaleType and then applying a ScaleAnimation directly to that ImageView:
Layout:
<ImageView
android:id="#+id/graphImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:scaleType="centerCrop"
android:background="#android:color/transparent"
android:contentDescription="#string/stroom_grafiek"
/>
Java:
scale = new ScaleAnimation((float)0,
(float)1, (float)1, (float)1,
Animation.RELATIVE_TO_SELF, (float)0,
Animation.RELATIVE_TO_SELF, (float)1);
scale.setDuration(1000);
graphImage.startAnimation(scale);
But this stil scales the image.
I also tried wrapping the ImageView in a FrameLayout, hoping I could just animate the FrameLayout:
<FrameLayout
android:layout_width="70dp"
android:layout_height="fill_parent"
android:clipChildren="true"">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left|clip_horizontal" />
</FrameLayout>
This will still try to scale my ImageView to fit inside the FrameLayout.
There are several ways to do this - one way is to simply change the clip on the canvas (i.e. the area where the view is allowed to draw) of the ImageView drawing your image. Slowly increasing the right-hand edge of the draw bounds will result in same effect as in your example link.
I have written some example code which illustrates this technique. If you download/build/run the project, clicking on the image will run the reveal animation.
Have a look at the onDraw method of the CoveredImageView class, which has the following basic structure:
#Override
protected void onDraw(Canvas canvas) {
...
canvas.getClipBounds(mRect);
mRect.right = ...;
canvas.clipRect(mRect);
...
super.onDraw(canvas);
...
invalidate();
}
The clip is adjusted and then invalidate() is called, causing onDraw() to be called again.
I have also written some code to interpolate the right clip value from the elapsed time, which does not depend on any particular version of Android. However, as a note, from Android 3.0 there is a new animation framework and a ValueAnimator class which could help perform such tasks.
You could overlap your imageview with another one, for example one with a plain white drawable. Then you can animate the overlapping imageview without worrying about scale until it has a width of 0 and remove it. For that to work you have to place your imageView in a RelativeLayout ofc.

Android Camera Preview centered in an image

I am creating a Camera application where I want to restrict the camera preview to be centered and around 60% of total size of the phone screen.
One way is to have the FrameLayout of Preview with padding so that the usable screen size is restricted , but I also want to show borders (around the corners) inside the restricted area which is not possible in this options.Also it not possible to show padding in percentage so that I can restrict user to 60% of screen size.
Other way is to have a image having a transparent center rectangular area and having border in inner rectangle corners . But I somehow need to restrict the FrameLayout of preview inside this rectangle which I am not able to do . Any suggestions on this option ?
Please also let me know if there are any other options .
Thanks.
Unless I don't fully understand your issues with using android:padding to provide space around your layout, you should be able to use android:layout_margin instead to accomplish the same goal but overcome the problems you mentioned. Adding padding creates space between the border of the View and its content. However, adding margin creates space between the border of the View and its parent, so the content still fills the View itself to the edges. However, you still can't define your view spacing in terms of percentage direct from XML...you would need to define the margin as static or apply the LayoutParams in Java code where you could calculate the required margin based on the current screen size.
Another option is to take advantage of the android:layout_weight property inside of a nested LinearLayout. The calculated weight sum could give you the 60% you're looking for directly in XML. Something like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:weightSum="1.0" >
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.6"
android:gravity="center"
android:weightSum="1.0">
<SurfaceView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.6" />
</LinearLayout>
</LinearLayout>
Where the SurfaceView is the location of your Camera Preview, now centered with 20% of the screen on all sides. If you wanted to place things over or under this preview you would obviously want to place this entire block into a RelativeLayout or FrameLayout along with other components.
HTH!

Categories

Resources