I am working on a custom view where I would like to display a single post from Facebook in a custom View, it would include the name of the person who made the post, the updated time, the message itself or post content and the handle that lets a person expand or collapse the post with a 'Read More' or 'Read Less' depending on how big the post is.
The code for my Custom View looks like this http://pastebin.com/VkxpfLnj , and my animation class looks like this http://pastebin.com/HsEadatY
The problem with the message part is it can be very huge and hence I need an expand or collapse handle. I create a new StaticLayout object everytime the text changes.
I took 3 approaches to animation
based on the difference in the number of pixels, suppose my post was 300 pixels tall before expanding and after expanding was 700 pixels tall, I would simply animate between these two, the problem is that I have to call requestLayout each time and it results in 40 calls per expansion or contraction
The other approach I tried out was to animate based on the number of lines , if there were 4 lines before expansion and 8 lines after expansion,I would simply increment the height of the postview by line height * (final number of lines - initial number of lines )* interpolated time, this approach gave me a just 10 requestLayout() calls but laggy animation.
As per my ViewUtils animation method, my current approach calls requestLayout only at the beginning, the center and end of the animation and results in roughly 12 requestLayout() calls per expand or collapse.
How can I use the static layout or for that matter draw multiple lines on canvas in such a way that I can fade in text when I expand or collapse and at the same time keep the number of requestLayout() calls to a minimum. I would also like to make this Canvas support LTR and RTL if possible. Any suggestions?
Related
I am trying to understand the hierarchy view.
So I was reading on developer.android.com the meaning of the three dots :
Green: For this part of the render time, this View is in the faster
50% of all the View objects in the tree. For example, a green dot for
the measure time means that this View has a faster measure time than
50% of the View objects in the tree.
Yellow: For this part of the
render time, this View is in the slower 50% of all the View objects in
the tree. For example, a yellow dot for the layout time means that
this View has a slower layout time than 50% of the View objects in the
tree.
Red: For this part of the render time, this View is the slowest
one in the tree. For example, a red dot for the draw time means that
this View takes the most time to draw of all the View objects in the
tree.
If I'm not mistaken, doesn't that mean that there should always be at most 3 views with red dots (the slowest views for each category : measure, layout, draw), and then half of views yellow and half green.
First of all I see more than 3 views with red dots and I don't understand why.
Second, I don't see how these values can help improve performance considering that these are relative values. There will always be half of the views faster than the other half.
And looking at the Tree View I am seeing views with visibility gone that have a small draw time. Shouldn't GONE views be completely ignored?
If I'm not mistaken, doesn't that mean that there should always be at
most 3 views with red dots
Your logic is good, but the document must not say tree but at a node. The tool4s function of the hierarchy viewer you use to get these 3 dots is Profile Node, and this will start to profile the tree from the selected node (the arbitrary root of the tree) to the end of the tree.
Every View, into a ViewGroup (layouts are based on ViewGroup) which contains more than a View, will have the dots. In the opposite case there is no dots.
So the comparison is only made on a node level, not for all the tree, and this is why you can get more that three red dot (one for measure, one for layout, one for draw) for all the tree, but not for a node.
Second, I don't see how these values can help improve performance
considering that these are relative values. There will always be half
of the views faster than the other half.
The Dots help you to know which view inside a view group is the slowest to Measure/Layout/Draw. To avoid the screen to freeze, the total of an operation must be under 16.6ms (android should keep a frame rate of 60 frames per second).
The red dot will just give you an hint about which view you should profile but this doesn't mean that a view is not optimized, especially with a complex hierarchy with lots of children.
Also if you have to build a custom view, the hierarchy viewer can help you to know if you are correctly doing a quick rendering.
I am seeing views with visibility gone that have a small draw time.
Shouldn't GONE views be completely ignored?
A View which has a visibility set to GONE will not go through onMeasure, onLayout and onDraw. You can easily try it if you extends a widget like a TextView and override these methods with a Log.d to know what happen.
But I guess the time on draw comes because the view will be created, then attach to the window and finally change its visibility.
Example with a TextView. First step the object is created via the java constructor public Text(Context context, AttributeSet attrs){...} ), then a call to attach the window will be performed with protected void onAttachedToWindow() {...} and the visibility changed with protected void onWindowVisibilityChanged(int visibility) {}
Now if you want to debug more your U.I., try with a phone which have the option Debug GPU Overdraw into the Developer Options (not all the phone have it) or with the emulator. You can then see where the app is overdrawing and then optimized your interface.
Debug GPU Overdraw walkthrough
I'm tackling the task of an overlaying drawable over a view that animates the drawing of a checkmark as in the following video https://vid.me/MsQj
I don't have a preferred method for doing this but it's just not coming out the way I wanted it to, I tried:
Two views, each with on side of the checkmark to be revealed with an animation, however I'm stuck at the "revealed with an animation" since I can't use the circular reveal on -21
Frame by frame animation, this is the easiest but I'd hate to have 60 images for this stupid animation if it can be done programmatically
Drawing on a custom view canvas
My question would be, is there anything that can make this easier on me, or do I have to tackle it head first and just get on with it
You could create a custom View class which contains two lines defined by ShapeDrawables, one for each leg of the tick. Expose the lengths of these two lines as properties of the class, and then use Property Animation to animate the lengths of the lines.
Property Animation is flexible enough to handle pretty complex timing and sequencing of various properties. In this particular case you would probably want to use an AnimatorSet to sequence the two line animations so the second starts once the first has finished.
I ended up developing a custom View thanks to #SoundConception suggestion and finding out about ObjectAnimator which are very powerful in Android. In essence what goes on is we set a width for the first and second line that make the checkmark and using the animator change the value of those properties from 0 to the desired one.
On the setter for the property, we invalidate the View to redraw it with the new value and with a little tweaking I made a nice View that while its currently only working for my specific layout (ie it needs some more work on the offset calculation) it's able to draw an animated checkmark with some stuff that is customizable.
Precisely, you can set the line width, the color, the length and the animation time. And touching the java file, you can change the interpolator and all the rest of the stuff.
Hopefully the code, while not really commented serves as a basis for someone trying something similar.
For example the following code would generate something like this video, although not really because I was testing opacity and thinner lines, but you get my drift.
<coop.devtopia.CheckmarkView
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_centerInParent="true"
android:id="#+id/view"
app:first_leg_length="50"
app:second_leg_length="100"
app:total_duration="1500"
app:stroke_width="20"
app:stroke_color="#22000000"/>
Repository
Update 4/2/15
I've played with this a little further and added dynamic offset calculation (fancy way of saying centering) to the tick, meaning we can generate big checkmarks, small checkmarks, skinny or thick, reversed or straight and they will be centered in the view. Can't guarantee the same for checkmarks bigger than the container, they will likely be cropped.
Here are a few of the checkmarks generated for this demonstration, of course the animate as if drawn and the effect can be very pleasing and resource friendly. This turn out to be a pretty interesting subject after all.
Is it possible to rotate views in XML with APIs previous to Honeycomb - maybe with the support package? Or is the only way to create a custom class, like described here Vertical (rotated) label in Android
Edit: What I need is a statically rotated view (specifically a TextView, but I guess it's enough to know how to do it with a View). Starting with honeycomb there's a rotation attribute which can be used in XML. I need something like that.
The only thing I have found until now is use an animation with duration 0 but this still moves a bit at start and I don't want that. I tried setting the views invisible and attaching a listener to the animation which makes them visible on animation finished callback, but that made strange results... that changed the position of the views, for some reason.
The best way is with the custom subclass implementation that you linked to, where you can rotate the canvas and resize the view appropriately. This ensures that the view bounds are also set to match the text that is drawn.
The only method of transforming views externally prior to HC is the animation framework, and applying an Animation to the view with a duration of 0 and fillAfter set to true will work, but you may notice flickering on some devices as often the view will render normally on its first frame and then animated to its final position from that point onward. You can work around this by hiding the view and displaying it a bit late...but you can see how hacks are starting to stack up.
In addition, doing an Animation prior to HC will not transform the view bounds themselves, so you won't be able to neatly pack other views around this one because its position from a layout perspective will still be the rectangle calculated for the horizontal (non-rotated) text.
The simple subclass is definitely the preferred method.
HTH
Is it possible to rotate views in XML with APIs previous to Honeycomb
There is RotateAnimation. However, depending on what you are trying to accomplish, that may not meet your needs.
I have a bit specific problem, but hopefully someone will chime in and help.
I've written a custom zoom animation (posting runnables that change the target view to a handler between certain amount of time) but when i change the view's width and height it is as if I've performed a zoom around (0,0) of the view whereas I want to zoom around its center so I move the view by changing its margins accordingly. The thing is though that when the zoom iteration step is too small (i.e 0.01f and less) I have to change the margins of the view by something like 1px sometimes only in one of the directions which makes it look as if the animation is glitchy. I'm not sure of the exact reason but I've tried the following things:
1) I tried changing the margins by overriding onLayout() of my parent view which will be caled when setting the layoutParams upon zooming( I did this in order to avoid a second call to setLayoutParams() upon moving which actually now doesn't seem quite reasonable since setLayoutParams() just sets some flag which will be used later on).
2) I'm checking the new margins to set so that they are set only when there's a difference between the new and the old margins in both X and Y directions.
3)I tried using view.offsetLeftAndRight() view.offsetTopAndBottom() instead of changing the layout params in order to move the view, but it was again to no avail.
Any suggestions what will do the trick?
If I undestand you correctly you need to get Bitmap cache from view and draw it manually. In this case bitmap will be drawn without glitches (if Bitmap filtering is on).
You can do it in following steps:
get view cache - through View.getDrawingCache or by calling View.draw function
hide view
get current system time - SystemClock.elapsedRealtime (thanks to this you can calculate animation progress)
start posting runnables to invalidate your screen and check whether animation is ended
show view
Possibly it can be done via Android Animation class but I do not use it as it quite limited.
I need your advice on the best way to implement a scrollable playing field in a simple game. The field consists of multiple rows, with 9 cells in each row. The rows can be dynamically added and removed during the course of the game. Each cell has a digit in it, and optionally several overlayed images, like selection, selector over, crossed out, etc. (see the pic below). The user should be able to click on individual cells of a row to select/deselect/cross the touched cells. At any point in the game there can be from 0 to 3000 cells (0 to about 333 rows). The field should scroll up and down smoothly.
I was thinking about having a ListView with its each row being a row on the field. That way i could add/remove rows dynamically during the game. However, how exactly should i implement a row: have one bitmap representing a row, and then when the user touches it -- get the coordinates of the touch area, and find out what cell was affected, and then act upon that. Is it possible to get the touch coordinates of a row in ListView? If not, should I place 9 dummy image placeholders in each row, and then act on user touching those? What about performance?
Or should I have one huge bitmap / canvas representing the entire field, place it inside a ScrollView and then calculate all the coordinates and update it as the user interacts with it? Is it going to be faster or slower than the ListView?
Any other solutions?
I prefer it to be a "regular" app type game, not a loop-based game, as I don't think I really need to redraw 30 times a second.
I am pretty new to Android. Thank you for your suggestions.
You can easily make that kind of setup run quickly with a "game loop" / SurfaceView combination. That means no ListView, only custom drawing and event handling. Luckily the event handling isn't that difficult, and you'll win later on because you'll have much greater control over the interface than if you had gone with a bunch of customized views and layouts.
I'd avoid that www.droidnova.com tutorial, it uses HashMaps unnecessarily, which will only cost you in performance.
Here's how I'd go about it:
Create an object to hold your cell data. For this example, I'd use an object with an id (to print), and an x and y for where to draw on the screen.
Decide on a board size which will fit on your screen without scrolling, say 10x10. You'll add the scrolling later.
Create a 2-dimensional array of cell objects with lengths boardSize x boardSize. Fill the objects with id and x and y position on the screen.
In your custom onDraw, iterate through each "row" and "column" of your single array and draw the object at its stored x and y value.
So now you've got a grid of objects displaying on your screen. Now you want to restrict the number of rows currently displayed and add some functionality to change which rows are visible. This is done as follows:
During initialization, set up some global ints as mCurrentRow = 0 and mNumVisibleRows = 3. These define your "view window".
Modify your drawing code to only draw rows starting at mCurrentRow and ending at mCurrentRow + mNumVisibleRows. The result of this should be that you only ever see mNumVisibleRows rows, and which group of rows you see depends on what you set mCurrentRow to.
Add some triangles to the right of your grid drawing and have tap touch events in those areas map to increments/decrements of mCurrentRow. Obviously, you should not allow that value to go outside your row count bounds.
If you want to get classy, draw a line between your triangles for a scroll area, and map touch events there to something like newCurrentRow = (touch.y / canvas.height()) * boardSize; That needs some tweaking, but you get the idea.
This approach has the downside of only showing a full set of rows at a time, so scrolling wouldn't be smooth. However, you have complete control over your canvas and what you draw, so with a little more math you could implement a smooth scrolling mechanism which would offset by a fractional row height in the y-direction instead of whole rows.
I dont know if you can create a game like you described with good performance. I would look into basic tile game programming.
But by avoiding the standard view components are have to write all the logic yourself requires quite some work. Things like handling "click" events on different rows needs to be calculated by the tile position relative to the game camera. So theres alot of new stuff in learning to develop game at a lower level.
You also have to take the rendering of your game into your own hands by developing a game loop that constantly updates and draw's your tiles from a background thread to reflect the scroll / state of your game.
You can get more infomation on the basics of a game loop at:
http://www.rbgrn.net/content/54-getting-started-android-game-development
If you want to learn more you should see the following keynotes from android.
http://developer.android.com/videos/index.html#v=U4Bk5rmIpic
http://developer.android.com/videos/index.html#v=7-62tRHLcHk
Those give you a very good insight in developing games for andriod at a low level where you can fine tune for performance.