catch notes like animation - android

I need to create an animation like in the "Catch notes" app. The animation that I am referring to is when you press on an object in a list, all of the object above it go up and all of the objects below it go down, all with animation.
I was thinking that it could not be possible by using a regular list view. so maybe the way to do it is just to put the objects manually one by one in some way?
Any better ideas?
Thanks!

Get all visible items (listView.getFirstVisiblePosition() to getLastVisiblePosition()) and get there views with listView.getChildAt(index).
Then you can animate all the views above and below your view with ObjectAnimator or similar.
Example:
for (int i = listView.getFirstVisiblePosition(); i < myListAdapter.getCount() && i <= listView.getLastVisiblePosition(); i++) {
View v = listView.getChildAt(i - listView.getFirstVisiblePosition());
ListItem listItem = myListAdapter.getListItem(i);
if (v != null) {
ObjectAnimator.ofFloat(v, "translationY", 0, -screenHeight).start();
}
}

Related

Compare Drawables on ImageViews

I'm trying to create a One-armed Bandit app.
I have created an animation xml file to go through multiple images. When a button is clicked, the animation stops.
My question is how to compare the picture that one animation stopped on with that of another? So far I've tried something like this:
if(wheel1.getBackground().getConstantState().equals(wheel2.getBackground().getConstantState())) matches++;
Any help is appreciated.
you must be starting the animation with .animationStart()
just use .onAnimationStop() and it will trigger the event automatically.
A View should not maintain application logic, the controller (your hosting Activity or Fragment) should.
That said, to achieve what you want use View.setTag() to apply a logical description of each View to it.
Then when stopping animation, loop through all Views you have and get their position on screen, get the Views mostly visible in each column of your bandit machine and compare their tags (View.getTag())
for example, if the items animate vertically use below method to determine where the bandit stopped.
//the area where to compare views
int BOUND_TOP, BOUNT_DOWN;
//your content view
ViewGroup rootLayout;
//method to get information about what is visible
public List<Object> getVisibleViewTags() {
List<Object> list = new LinkedList<>();
int count = rootLayout.getChildCount();
for (int pos = 0; pos < count; pos++) {
View child = rootLayout.getChildAt(pos);
float translationY = child.getTranslationY();
if (translationY > BOUND_TOP && translationY < BOUND_DOWN) {
list.add(child.getTag());
}
}
return list;
}
Now you just need to attach information about a view as tag to it.
example:
view.setTag("view_apples");
or
view.setTag("view_bananas");

How to duplicate Jelly Bean "clear all notifications" animation

I'm trying to implement the same kind of animation that happens when clicking the "clear all" button in the notification bar:
This is what I have now (for a ListView) but it's not working correctly. Because of timing/pauses, I think.
Animation animation = AnimationUtils.loadAnimation(getActivity(), android.R.anim.slide_out_right);
animation.setDuration(300);
int count = mNotificationList.getCount();
for (int i = 0; i < count; i++) {
View view = mNotificationList.getChildAt(i);
if (view != null)
view.startAnimation(animation);
}
Anyone knows how to accomplish the animation?
In order to achieve such an effect you should use a different Animation for each item, so you can easily set different starting offset via Animation.setStartOffset(long) method.
Your code should look like this:
int count = mNotificationList.getCount();
for (int i = 0; i < count; i++) {
View view = mNotificationList.getChildAt(i);
if (view != null) {
// create an Animation for each item
Animation animation = AnimationUtils.loadAnimation(
getActivity(),
android.R.anim.slide_out_right);
animation.setDuration(300);
// ensure animation final state is "persistent"
animation.setFillAfter(true);
// calculate offset (bottom ones first, like in notification panel)
animation.setStartOffset(100 * (count - 1 - i) );
view.startAnimation(animation);
}
}

Get all full visible objects on lListView

I have a ListView, which contains more elements then I can display at one time.Now I want to get Index off all Elements, which are full visible ( -> excluding those that are only partially visible).
At this moment I use getFirstVisiblePosition() & getLastVisiblePosition() into an for-loop to iterate them, but these method is not accurate as I want to.
Is there any better solution?
A ListView keeps its rows organized in a top-down list, which you can access with getChildAt(). So what you want is quite simple. Let's get the first and last Views, then check if they are completely visible or not:
// getTop() and getBottom() are relative to the ListView,
// so if getTop() is negative, it is not fully visible
int first = 0;
if(listView.getChildAt(first).getTop() < 0)
first++;
int last = listView.getChildCount() - 1;
if(listView.getChildAt(last).getBottom() > listView.getHeight())
last--;
// Now loop through your rows
for( ; first <= last; first++) {
// Do something
View row = listView.getChildAt(first);
}
Addition
Now I want to get Index off all Elements, which are full visible
I'm not certain what that sentence means. If the code above isn't the index you wanted you can use:
int first = listView.getFirstVisiblePosition();
if(listView.getChildAt(0).getTop() < 0)
first++;
To have an index that is relative to your adapter (i.e. adapter.getItem(first).)
The way I would do this is I would extend whatever view your are passing in getView of the ListView adapter and override the methods onAttachedToWindow and onDetachedToWindow to keep track of the indexes that are visible.
Try onScrollListner and you can able to use getFirstVisiblePosition and getLastVisiblePosition.
This this link, it contain similar type of problem. I suppose you got your answer there..,.
The above code is somewhat correct. If you need to find the completely visible location of view use below code
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
View v = null;
if (scrollState == 0) {
int first =0;
if (view.getChildAt(first).getTop() < 0)
first++;
int last = list.getChildCount() - 1;
if (list.getChildAt(last).getBottom() > list
.getHeight())
last--;
// Now loop through your rows
for ( ; first <= last; first++) {
// Do something
View row = view.getChildAt(first);
// postion for your row............
int i=list.getPositionForView(row);
}
}
// set the margin.
}

Sometimes listView.getChildAt(int index) returns NULL (Android)

I have a listView with a custom adapter. When something happens (a click in a child) I do some calculation things and modify the child View. IF some condition has been fulfilled then other child unrelated to the clicked child should be modified.
This sometimes works, but sometimes fails and the DDMS says that the view is null...
Let me show you the code:
if(invalidaEste != -1)
{
try
{
View v = lv_data.getChildAt(invalidaEste);
if( v== null)
{
Log.e("MY_LOG", "SIZE " + lv_data.getCount());
Log.e("MY_LOG", "IS_NULL " + String.valueOf(invalidaEste));
}
if(invalidaEste >= lv_data.getFirstVisiblePosition() &&
invalidaEste <= lv_data.getLastVisiblePosition())
{
RelacionFacturaPago rpf = (RelacionFacturaPago)lv_data.getAdapter().getItem(invalidaEste);
TextView tv = (TextView)v.findViewById(R.id.tv_pendiente);
tv.setText(Formato.double2Screen(rpf.getPorPagar()));
}
}
catch (Exception e)
{
Log.e("MY_LOG", "FAIL");
Log.e("MY_LOG", String.valueOf(invalidaEste));
}
}
invalidaEste is the view that I want to modify.
When v is null I log the index to check if it is OK. Always is smaller or equal than the listView.getCount()
Why is this happening?
More data: The code is inside of the onAnimationStart(Animation animation) of an AnimationListener listener.
Because of view recycling, listView.getChildAt() will only return a view for the positions it is displaying, and maybe one more. Maybe if you share more of your code we can help you figure out how to best tackle the problem.
Dmon and Azertiti are both correct... once your list is scrolled you find yourself in trouble. If the view isn't visible, then it doesn't exist (i.e. has been recycled by Android). You'll re-build the view once it's scrolled in.
Doing something like this should work:
View view;
int nFirstPos = lv_data.getFirstVisiblePosition();
int nWantedPos = invalidaEste - nFirstPos;
if ((nWantedPos >= 0) && (nWantedPos <= lv_data.getChildCount())
{
view = lv_data.getChildAt(nWantedPos);
if (view == null)
return;
// else we have the view we want
}
If that child is not visible on screen it means there is no View for it. I believe this is your not working case.
A good practice is to change the data behind your list adapter and call notifyDataSetChanged() on the adapter. This will inform the list the adapter has changed and paint again the views.
If you really want to manually update the view I guess the only solution is to retain the new values somewhere and wait until the View becomes visible. At that point you have a valid reference and can do the updates.
I test it with one line of code when I need to go within a valid position of a Listview. here is your variables used as an example. where lv_data is the ListView and tv is your TextView.
if ( lv_data.getChildAt(lv_data.getPositionForView(tv)) != null) {
int position = lv_data.getPositionForView(tv);
}

Commonsware Drag Drop shrinks row height permanently

I did get the drag and drop working and the TouchListView class works great. However in my case I have rows of various height due to my adapter which contains an EditText that can have multiple lines. Therefore after I drop, all my rows convert to the tlv:normal_height which in my case is 74dip. This causes many rows to cut off all my text in the EditTexts. I tried re initializing my adapter (mylistview.setAdapter= myadapter), setting the ListView to GONE then VISIBLE and invalidateViews() but nothing seems to reset the ListView back to before I dragged, short of leaving the activity and coming back. What can be done here? -Thx
tlv:normal_height="74dip"
tlv:expanded_height="128dip"
There's little question that the original AOSP code was designed for uniform row heights, and the whole expanded_height construct was there to provide space for the user to visualize where the drop would occur.
One starting point would probably be to create a TouchListAdapter mixin interface (akin to SpinnerAdapter) where the normal_height and expanded_height would be retrieved dynamically from the adapter based on position as opposed to being fixed values declared in the layout. Whether that alone would be sufficient or more work would need to be done, I can't say.
If you come up with a solution, patches are welcome. Otherwise, I'll probably take a look at this sometime, but not very soon.
My apologies for not having a near-term silver bullet.
I edited the unExpandViews() method - called getAdapter() and for every item in my adapter set the height to 0 and then all the rows were set back to original. I also bypassed the delete part of the method since it did not apply to me.
private void unExpandViews(boolean deletion) {
int height_saved = 0;
CheckBoxifiedTextListAdapter cbla = (CheckBoxifiedTextListAdapter)getAdapter();
for (int i = 0;i < cbla.getCount(); i++)
{
//View v = getChildAt(i);
View v = cbla.getView(i, null, null);
//if (v == null)
//{
/*
if (deletion)
{
// HACK force update of mItemCount
int position = getFirstVisiblePosition();
int y = getChildAt(0).getTop();
setAdapter(getAdapter());
setSelectionFromTop(position, y);
// end hack
}
layoutChildren(); // force children to be recreated where needed
v = getChildAt(i);
if (v == null)
{
break;
}
height_saved = v.getHeight();
*/
//}
//else
//height_saved = v.getHeight();
if (isDraggableRow(v))
{
ViewGroup.LayoutParams params = v.getLayoutParams();
params.height = 0;
v.setLayoutParams(params);
v.setVisibility(View.VISIBLE);
}
}
}

Categories

Resources