redundant onDraw() calls in FrameLayout - android

I have the following layout structure in my xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainlayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<MyEntireView
android:id="#+id/map"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</MyEntireView>
<FrameLayout
android:id="#+id/focusedlayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom">
<MyDetailedView
android:id="#+id/focus"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</MyDetailedView>
</FrameLayout>
</FrameLayout>
MyEntireView is a map (a Drawable) and MyDetailedView pops up on top of it upon onTouch() and contains only a certain piece of the whole map (also Drawable) that displays in greater detail the area which the user touched on the entire map in MyEntireView.
When MyDetailedView is shown - i.e. its setVisibility(View.VISIBLE) - there appear some transparent shapes (also some Bitmaps) on top and are redrawn regularly (e.g., 1 sec interval). The shapes are added dynamically as children of the #+id/focusedlayout as there is always a different number of them and their position is relevant to the detailed map picture.
And the problem is that each single update is processed multiple times. Each time a shape updates, then MyEntireView's onDraw() is called, MyDetailedView's onDraw() is called, and then these two are called again. And only after this the shape itself is invalidated.
As a result, this behaviour makes the shape flicker, since MyDetailedView redraws and hides the shape for 10ms or so.
I must probably be overlooking some simple logic, but I really can't get if there is a way to force only one View of a ViewGroup invalidate().
Or maybe there is an alternate structure/layout that I could use to fit my purpose?
Thanks a lot!
P.S.
The entire code is quite big to put here but I'm willing to insert any pieces upon request

Related

Approaches for implementing Android animation that re-apportions view

I have a LinearLayout that contains a couple of views. It doesn't have to be LinearLayout-based - this is negotiable - but it provides this simple example.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/left"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#f00"
android:orientation="horizontal"/>
<LinearLayout
android:id="#+id/right"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#ff0"
android:orientation="horizontal"/>
</LinearLayout>
This is rendered as follows:
What I want to do is produce an animation sequence that slides out the yellow view, off the right of the screen, whilst simultaneously enlarging the red view to fill the space left behind.
It strikes me that there are a few ways to do this:
Weight-Based Animation
I can change the layout weight - specifically, iteratively reduce the yellow view's weight to zero. This will do the job as far as the red view is concerned. However if the yellow view has content in it, it will be squashed as it resizes down. It also doesn't run very smoothly.
This is almost acceptable in some contexts, because I can fade out the yellow view and its content to an alpha of zero, and then clear the empty space. Still not that smooth, but no squashing. However when I need the content to stay visible while moving, it ceases to be appropriate anyway.
Translation Animation
I can slide out the yellow view, a bit like this. However the vacated space is left behind, as you might expect. It does run perfectly smoothly.
A combination of the above?
I haven't tried this yet. I guess I could slide out the view whilst simultaneously reducing the weight of the empty space. I don't know if this is actually feasible, i.e. whether the weight change would affect the animated slide, or whether the two can be coherently run at once, or whether it will operate smoothly anyway.
Or, of course, something entirely different.
Any suggestions please?

Rotated ListFragment disappears when empty view displayed after Filter

Just to be clear, we're talking about an XML rotated view here, not the effects of rotating the device. I have a SlidingDrawer that contains a ListFragment. The ListFragment implements the Filterable interface so that users can search its contents by providing a string input through an EditText.
The relevant layout is included below. Because the SlidingDrawer class was deprecated in API 17, the source code was copied over an accessed via a local class. That's why the name of that view looks like a custom class when really it's not.
<com.example.echo.views.SlidingDrawer
android:id="#+id/left_sliding_drawer"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:handle="#+id/left_handle"
android:orientation="horizontal"
android:content="#+id/people_fragment_container"
android:rotation="180">
<LinearLayout
android:id="#id/left_handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/people_tab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/people_map_tab_grey"
android:rotation="180"
android:contentDescription="#string/people_tab"/>
</LinearLayout>
<FrameLayout
android:id="#+id/people_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.example.echo.views.SlidingDrawer>
What happens is, when the users provides input and filters the list such that there are no matching results, i.e., the ListView is empty and size is 0, the entire SlidingDrawer disappears.
Some things I've noticed in trying to fix this:
I am pretty sure this is related to displaying the empty view and/or whatever layout change occurs when it is displayed. If I simply do not set an empty view for the ListFragment the issue does not occur.
I am also pretty sure the effects are related to the fact that the SlidingDrawer is being rotated by 180 degrees since, if I remove the rotation attribute, the issue also does not occur. However, because SlidingDrawer in its default state only opened right to left, this drawer applies the XML attribute android:rotation="180" to flip the view so that it can be opened left to right. This must remain since there is other stuff on the right side of the screen that cannot be moved.
I'm not sure what is making the view disappear or where to start fixing it. I've trying fixing the child views' sizes by overriding onMeasure, onSizeChanged, and onLayout but cannot find anything that solves the issue.
Any ideas are appreciated.

Android: how can I add different layer to a image view dynamically?

I have one fragment layout with a background image. Programmatically I have to add the different layer to this image because I want to add some particular details depending of some data. There are three different details that it can change in 3 different way. ( there is a thread that works at 5/10hz and it loads the right details)
The following is my first implementation. In this version, I have done all of works in XML layout and in a programmatically way, when the user clicks on a certain button, I set the visibility of each image view. I have seen that is much expensive, and sometimes the inflate layout return null:
<RelativeLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/background"
>
<ImageView
android:id="#+id/layer1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:src="#drawable/ballgreen"/>
<ImageView
android:id="#+id/layer2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:src="#drawable/ballred"/>
<ImageView
android:id="#+id/layer3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:src="#drawable/ballyellow"/>
... 6 more image view layer....
</RelativeLayout>
Then I thought to use an async task to decode all drawable image, make a bitmap fusion and in a post execute load the result bitmap in a single image view.
But the asynctask is not the better way to implement, because the user can click on that button many times and each time I have to call new asynctask ..
Are there a clever ways to implement all of this?
Goodbye and thanks a lot :)
EDIT : each layer is a detail that thread can add to that image.
For example : a car, a tree, a red ball ecc ecc. In the xml example for me each imageview is a layer, and this is wrong. But I don't know the clever way to implement ..
EDIT2 : Moreover I know the maximum amount of layer, but there are many combinations. there are 3 point and for each point I can choice between 3 differents details
Edit3: i add some details , there is a thread that change laYer and not the user
Use the LayerDrawable class, adding new layers as the user enables them. I don't think you can remove layers from it, but you can create a new LayerDrawable each time the user disables a layer. Or you can use setDrawable(int, Drawable) to replace a layer.
This means you don't have to complicate your layouts, and should get rid of those pesky extra inflation/measure/layout passes.
As for the image loading / async task stuff: use an LRU cache for your bitmaps. When a layer is enabled, check the cache, and if it's there, just use it. Otherwise, use an async task to load it.

Android GLSurfaceView in ScrollView produces black borders

I have a GLSurfaceView that I want to put inside a ScrollView. I accomplished this by adding a FrameLayout inside a LinearLayout which was added to the ScrollView.
Everyhing works nice, except that I am getting a black border on top of the GLSurfaceView when scrolling. When the screen is still, everyhing looks nice. Anybody have any ideas.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="900dp"
android:orientation="horizontal"
android:layout_weight="1"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="35dp"
android:visibility="visible"
android:weightSum="1"
android:overScrollMode="never">
<FrameLayout
android:id="#+id/ecg_graph"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Generally speaking, you don't want to move SurfaceView (or its subclasses) around the screen. Bear in mind that SurfaceView has two parts, the Surface and the View. The View part -- usually just a transparent "hole" used during layout -- is handled by the app. The Surface part is a separate graphics layer composited by the system, and its size and position are managed by the Window Manager.
When you move a SurfaceView, the View part moves immediately, but the Surface lags behind, because moving it requires communicating with other processes. You should expect to see a black bar in the direction that the View is moving, because you've temporarily exposed an area outside what the Surface covers.
The preferred way to handle this is to use a TextureView, which behaves just like other Views. You would need to do your own EGL setup and thread management, since GLSurfaceView won't be handling those for you. You can find some examples in Grafika.

clickable image inside canvas

I have create a canvas in android and inside that i have multiple bitmap images.not i want to make these images click able.
I have tried following things so far..
I tried to add bitmap in image view as imageview has a setOnClickListner
but i think ImageView can't be added into Canvas , so i dropped this idea. because even Bitmap itself has no click events.
If you want to use Canvas, keep in mind that it is a low level drawing mechanism.
Therefore, you need to implement the click logic yourself.
Catch the coordinates of any incoming TouchEvent.
If the TouchEvent is a "touch down" (finger pressed) or "touch up" (finger released), depending on your choice, consider it to be a click.
Compare the click event coordinates to every attached image's bounding box to find which image was touched. Take the z-index into account in case of overlap.
Trigger an onClickListener.
You also have to keep the coordinates of all images and the corresponding onClickListeners somewhere in memory.
Other solution:
Use a Layout, possibly a RelativeLayout, in which you add the ImageViews as children.
I believe you're asking for something like that:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/background"
android:orientation="vertical" >
<ImageView
android:id="#+id/clickable_image"
android:src="#drawable/ic_image"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:clickable="true"
/>
</LinearLayout>
Now you have your background "setting the whole view as a wallpaper" in your own words, and then you have your image, which is clickable. In your code you implement onClickListener and attach it to your ImageView and it will do whatever you want it to do.

Categories

Resources