I am trying to render a RemoteViews instance onto a Canvas, like I do with a regular View. I use
RemoteViews.apply(context, null)
and it returns a FrameLayout with all the views nested and properly measured (location and size is correct,) but after using .draw on the returned view, it renders all elements with no values -- TextViews are empty, AnalogClock is reset at 00:00 and so on.
Any ideas? I'm lost :(
Not sure if the question is still actual. Nevertheless here is my experience with RemoveViews. It appears you cannot just call draw() on the returned view. You have to add this view to a parent container to make it a part of global view hierarchy. For instance, you have an Activity with a single FrameLayout in it. Your code will look like this.
FrameLayout parent = findViewById(R.id.container);
View view = RemoteViews.apply(getActivity(), parent);
parent.addView(view);
Now you should be able to see tests. If you set listeners, they will work properly too.
Related
I am trying to draw a View in a ViewGroup without adding it to the child list.
I am doing this because I want to display something like a ProgressBar in the exact center of layouts like a LinearLayout so I don't want the layout to handle the measuring and layouting.
I also don't want to complicate the view hierarchy by adding extra layouts just to achieve this effect so my solution was to extend the LinearLayout, create a ProgressBar and handle measuring, layouting and drawing for that view myself.
My implementation seems to work ok from what I tested but I am wondering if there is anything I am not noticing or if there are any problems that can appear in the future.
From what I understand calling addView also sets the child view's parent and calls dispatchAttachedToWindow, these methods are package-private so I can't call them myself.
Is there any side effect that can arise from calling measure, layout and draw on a view that has no parent and that was not "attached" to a window? Is there a safer way to achieve the same effect?
Thanks.
For example When we write the code
View view = inflater.inflate(R.layout.main_activity, null);
What does the Android system do?
Check out the source for the LayoutInflater. It's an abstract class, a concrete instance of which is obtained through getLayoutInflater().
In essence, the inflater creates a root view object (the root view group of the inflated XML), then does two passes through the XML tree to attach each child view. This is done recursively to handle 'include' and to fix up references between child views, for example in RelativeLayout, and is done top to bottom.
The first pass constructs the tree by instantiating each of the child views, top down recursively, and passes the XML attributes to the view constructor telling the view how big it should be. It then calls measure() for each child passing in restrictions determined by the parent (e.g. RelativeLayout with 2 child views each requesting match_parent) using a measure specifications object and asks the view how big it wants to be. If the view is itself a view group, it will use the same algorithm to measure it's children.
The second pass is the layout pass when layout() is called on each child to position itself within the view. The parent positions the view using the measurements calculated in the measure pass. onDraw() is called and is passed a Canvas created from the DecorView backing bitmap.
The finalised tree is then ready to pass to the window manager which is done by setContentView() or addContentView().
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/view/LayoutInflater.java#LayoutInflater
Inflating an XML layout in simple language means you are converting the XML in View. Then you can fetch each view declared in the XML using the parent/inflated View.
For eg -
View view = inflater.inflate(R.layout.main_activity, null);
Now, here view is the reference of the XML from which you can fetch all the views as,
TextView tv = (TextView)view.findViewById(R.id.tv);
For example, top level LinearLayout view has 300 child view. But device screen dimension only show 11 child view once. How android compute how many child views can show once? How a view know that it will be draw?
Edited
In my work, one case like this:
An parent LinearLayout view may be has hundreds child view. In order to better performance , my solution like this:like lazy load.
List list = new ArrayList();//contain entity object that use construct View object
Default load 5 child view.
Parent LinearLayout view last child view is custom Loading View, I have override it`s onDraw() method. If loading View is draw, that means i need get next 5 child view(get next 5 object from list,and create correspond view).
I want to know how android framework handle this case?
Have u used scroll bar inside the top level LinearLayout view and add child view on that layout that's simple...
An parent LinearLayout view may be has hundreds child view. In order
to better performance , my solution like this:like lazy load.
LinearLayout with(possible) hundreds of child views kind of contradicts better performance. I think what you're looking for is a ListView with an endless adapter(a simple google search will show how to implement it, not something that difficult). This adapter will start loading views(with a loading view showing while the new content loads) as soon as you get to the last loaded element.
If you still want to use a LinearLayout:
If you just want to make the LinearLayout fill the content of the screen when it's first laid out you could post a Runnable on one of your views in the onCreate method (if this is where you'll first populate the LinearLayout). In that Runnable find the height of the LinearLayout and compare it with the combined height of its currently present children. If the combined child height is smaller then the LinearLayout height then add more views to compensate.
If the LinearLayout is in a ScrollView and you want to add additional children when the loading view becomes visible then monitor the scrolling of the ScrollView and when the loading view becomes visible add new children. Seeing when the loading view becomes visible would be done by checking how much the user has scrolled compared with the combined height of the currently present children of the LinearLayout.
Initial response:
Your question is a bit ambiguous regarding what you want to know. If you have a specific problem you should start with that.
For example, top level LinearLayout view has 300 child view. But
device screen dimension only show 11 child view once.
Please don't get yourself in a scenario like this. That number of views is to big an will result in poor performance or even the app crashing if you run out of memory(as all those views will be kept in memory).
How android compute how many child views can show once?
Each View and ViewGroup has the onMeasure method to measure itself and its children if available. The LinearLayout will have its onMeasure method called and in this method it will measure its children(with the measure method) giving them some suggestions on how big should they be(the LinearLayout receives some suggestions on how big it should be from its parent). If you want to see how this is done have a look at the source code of the LinearLayout.
How a view know that it will be draw?
I don't understand what you want to know. To draw the view on the screen its onDraw method will be called.
I have a custom ViewGroup which has two children, a ViewPager and another subclass of ViewPager.
When I instantiate it from code, it displays fine. However, when doing so from XML, the second child was not showing. I confirmed by add other views above and below the custom ViewGroup from XML and it turns out that the view was vertically offsetting by some amount which led to the second child being truncated.
The measuring seemed fine since I got the correct gap between t and b in the onLayout(). So I tried the following in my onLayout() before calling layout() on the children.
b = b - t;
t = 0;
Voila.... its displays perfectly, which doesn't really make sense since there is a view above this one which means t being zero should overwrite it (or maybe its relative, I could be wrong).
Anyways, what bugging me is why the arguments to the onLayout() were obviously offsetting the view ?
I want to include a simple animation in my app where a view widget moves to another view widget.
The code I have written is:
TranslateAnimation animate = new TranslateAnimation(view1.getTranslationX(), view1.getTranslationY(), view2.getTranslationX(), view2.getTranlationY());
animate.setDuration(500);
view1.startAnimation(animate);
The problem is that view1 is a custom view inherited from ViewSwitcher whereas view2 is a Button. getTranslation() gives no such method exception for both.
How can I get the view's position on screen and is this the right way to do the animation ?
Note: The ViewSwitcher is part of a ListView item so it also needs to cross over its ListView boundary to get to the Button(just in case that makes a difference).
Methods like getTranslationX() and getTranslationY() simply return an offset value that may be applied to the actual view position, and not the position itself. You will want to use methods like getLeft() and getTop() to get the x/y position value of a view relative to its parent (in this case, the ListView).
If you need more global coordinates, use getLocationInWindow() or getLocationOnScreen() to get the view's position relative to the global display hierarchy. These methods do not return the position, but rather fill it into the int[] you provide as a parameter.
All of these methods can be called on any View.
HTH
Basically, I'm not sure, if you did everything correct..
As for me, the easiest way to implement animation in Android is to use ViewFlipper. Maybe you should consider wrapping your views with it.
Here you have some post about using translation and alpha animations with ViewFlipper in case you follow my suggestion http://kevinrohling.wordpress.com/2011/01/25/using-a-slide-transition-with-viewflipper/