Implement Google+ card liked animation via RecylerView - android

Previously, I implemented Google+ card liked animation (Video), by using technique mentioned in New Google Now and Google+ card interface
Override LinearLayout's onGlobalLayout to start animation, so that when activity first launched, we can see the slide up animation of cards.
Override ScrollView's onScrollChanged to start animation, so that during scrolling, we can see the newly visible cards being animated.
So far, I don't see any technique from RecylerView's example.
I was wondering, without using LinearLayout and ScrollView, can with achieve the same outcome, by using RecylerView? Is there any code example available? (So far, I unable to find one yet)

Add these lines in RecyclerView 's adaptor. Make a Variable for Each card i.e(convertView) here and initialise it.
int mLastPosition = 0;
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView card_head, card_body;
View convertView;
#SuppressLint("NewApi")
public ViewHolder(View v) {
super(v);
convertView = v;
}
}
Bind you view by position
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// do your thing here
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
float initialTranslation = (mLastPosition <= position ? 150f
: -150f);
holder.convertView.setTranslationY(initialTranslation);
holder.convertView.animate()
.setInterpolator(new DecelerateInterpolator(1.0f))
.translationY(0f).setDuration(900l).setListener(null);
}
// Keep track of the last position we loaded
mLastPosition = position;
}
here , you have to animate the who view it calls onBindViewHolder method when new card is created animate the whole view customize it.

Related

Filtering Firebase data in adapter leaves empty space [duplicate]

I am using Firebase Recycler Adapter (Firebase UI Library) to populate Recycler View. I want to hide an item(row) on a condition.
I have a LinearLayout containing a recycler view.
I set linear layout visibility to Gone in populateViewHolder() method of recycler view adapter.
#Override
protected void populateViewHolder(UsersViewHolder viewHolder, User user, int position) {
if (user.getUserEmail().equals(Utils.decodeEmail(userEmail))) {
viewHolder.llMain.setVisibility(View.GONE);
return;
}
viewHolder.tvUserEmail.setText(user.getUserEmail());
}
It hides the LinearLayout but the row remains there with empty space.
Is there any method I should override to overcome this or is there any way to achieve the result?
In some cases changing only visibility attribute might still end up as allocated blank space (because of parent view's padding, margins, inner elements etc). Then changing height of the parent view helps:
holder.itemView.setVisibility(View.GONE);
holder.itemView.setLayoutParams(new RecyclerView.LayoutParams(0, 0));
Then be sure that in the condition that it should be visible, also set:
holder.itemView.setVisibility(View.VISIBLE);
holder.itemView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
You need to do that because the viewHolder is recycled as you scroll, if you change properties as this and never return them to their natural state, other elements will be already hidden in the event they reuse the same view.
You should hide all views or parent from UsersViewholder layout xml.
You should hide entire viewholder or each view
Entire viewholder:
itemView.setVisibility(View.GONE);
or each element:
view.setVisibility(View.GONE);
But don't forget to set them VISIBLE otherwise, you will end up with some strange things from recycling
IF
view.setVisibility(View.GONE);
gives you a Blank view
Then follow This.
public static class Data_ViewHolder extends RecyclerView.ViewHolder {
private final LinearLayout layout;
final LinearLayout.LayoutParams params;
public Show_Chat_ViewHolder(final View itemView) {
super(itemView);
.
.
.
layout =(LinearLayout)itemView.findViewById(R.id.show_item_layout);
params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
.
.
.
}
private void Layout_hide() {
params.height = 0;
//itemView.setLayoutParams(params); //This One.
layout.setLayoutParams(params); //Or This one.
}
}
Now Call from Adapter
mFirebaseAdapter = new FirebaseRecyclerAdapte......{
public void populateViewHolder.....{
if(model.getData().equals("..Something.."))
{
viewHolder.Layout_hide();
}
else
viewHolder.Person_Email(model.getEmail());
}
}
If you are hiding whole itemView and facing the problem of blank spaces.
Try this to hide the itemView.
holder.itemView.setVisibility(View.GONE);
ViewGroup.LayoutParams params = holder.itemView.getLayoutParams();
params.height = 0;
params.width = 0;
holder.itemView.setLayoutParams(params);
And this to show it.
holder.itemView.setVisibility(View.VISIBLE);
This is a recyclerView, so use both in if else block or you might encounter some unintended UI issues.
There is no built in way to hide a child in RecyclerView.
But you can implement this feature in your Adapter.
public class MyAdapter extends RecyclerView.Adapter<...>{
List<Object> items;
Map<Integer,Object> deletedItems;
...
public void hideItem(final int position) {
deletedItems.add(position, items.get(position));
items.remove(position);
notifyItemRemoved(position);
}
....
}
"GONE" will not remove the space occupied by the item ....you can use
if (condition) {
item.layoutParams.height = 0
item.layoutParams.width = 0
}
inside "onBindViewHolder"
public class OfferViewHolder extends RecyclerView.ViewHolder {
public TextView textViewOfferName;
public LabelImageView labelImageView;
public TextView textViewOldPrice;
public TextView textViewNewPrice;
public TextView textViewShopName;
public TextView textViewTimeDate;
public TextView textViewDistance;
public LinearLayout linearLayoutMain;
public OfferViewHolder(View view) {
super(view);
linearLayoutMain=(LinearLayout) view.findViewById(R.id.ll_main);
textViewOfferName = (TextView) view.findViewById(R.id.textViewoffername);
labelImageView=(LabelImageView) view.findViewById(R.id.labelImageView) ;
textViewOldPrice=(TextView) view.findViewById(R.id.textViewOldPrice);
textViewNewPrice=(TextView) view.findViewById(R.id.textViewNewPrice);
textViewShopName=(TextView) view.findViewById(R.id.textViewShopName);
textViewTimeDate=(TextView) view.findViewById(R.id.textViewDate);
textViewDistance=(TextView) view.findViewById(R.id.textViewDistance);
linearLayoutMain.setVisibility(View.GONE);
textViewOfferName.setVisibility(View.GONE);
labelImageView.setVisibility(View.GONE);
textViewOldPrice.setVisibility(View.GONE);
textViewNewPrice.setVisibility(View.GONE);
textViewShopName.setVisibility(View.GONE);
textViewTimeDate.setVisibility(View.GONE);
textViewDistance.setVisibility(View.GONE);
}
}`enter code here`
THEN IN YOUR ADAPTER
if (a.equals(offer.getOfferCategory())) {
if (offer.getOfferCategory()==null){
// chatMessageViewHolder.getLinearLayoutMain().setVisibility(View.GONE);
// chatMessageViewHolder.linearLayoutMain.setLayoutParams(new RecyclerView.LayoutParams(0, 0));
}
else {
chatMessageViewHolder.itemView.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewShopName.setText(offer.getOfferCategory());
chatMessageViewHolder.linearLayoutMain.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewOfferName.setVisibility(View.VISIBLE);
chatMessageViewHolder.labelImageView.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewOldPrice.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewNewPrice.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewShopName.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewTimeDate.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewDistance.setVisibility(View.VISIBLE);
}
Thank you lorescu George Cătălin and Dhalav
holder.itemView.setVisibility(View.VISIBLE); is not working now. I am using this
holder.itemView.findViewById(R.id.card).setVisibility(View.GONE);
you can easily send the ViewHolder value to your action function ..
I do not recommend answers with setting height and width of View to 0 because adapter still needs to render them and if there are too many hidden items this can cause lags, it is better to change the list itself and then send it to the adapter
It seems like RV internally caches root view info so changing it's visibility does nothing to occuppied space by the item.
Wrap you RV item view with FrameLayout and set View.GONE to inner view. This way occupped space will be cleared correctly as well as item won't be shown at all.
private fun hideShowItemView(itemView: View, toShow: Boolean) {
itemView.isVisible = toShow
itemView.layoutParams.height = if (toShow) ViewGroup.LayoutParams.WRAP_CONTENT else 0
}
itemView is an ItemView of the ViewHolder
toShow is a boolean to hide or show item of recyclerview
Use below line of code in onBindViewHolder block as per the requirement,
To hide Item : hideShowItemView(holder.itemView, false)
To show Item : hideShowItemView(holder.itemView, true)

How to hide an item from Recycler View on a particular condition?

I am using Firebase Recycler Adapter (Firebase UI Library) to populate Recycler View. I want to hide an item(row) on a condition.
I have a LinearLayout containing a recycler view.
I set linear layout visibility to Gone in populateViewHolder() method of recycler view adapter.
#Override
protected void populateViewHolder(UsersViewHolder viewHolder, User user, int position) {
if (user.getUserEmail().equals(Utils.decodeEmail(userEmail))) {
viewHolder.llMain.setVisibility(View.GONE);
return;
}
viewHolder.tvUserEmail.setText(user.getUserEmail());
}
It hides the LinearLayout but the row remains there with empty space.
Is there any method I should override to overcome this or is there any way to achieve the result?
In some cases changing only visibility attribute might still end up as allocated blank space (because of parent view's padding, margins, inner elements etc). Then changing height of the parent view helps:
holder.itemView.setVisibility(View.GONE);
holder.itemView.setLayoutParams(new RecyclerView.LayoutParams(0, 0));
Then be sure that in the condition that it should be visible, also set:
holder.itemView.setVisibility(View.VISIBLE);
holder.itemView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
You need to do that because the viewHolder is recycled as you scroll, if you change properties as this and never return them to their natural state, other elements will be already hidden in the event they reuse the same view.
You should hide all views or parent from UsersViewholder layout xml.
You should hide entire viewholder or each view
Entire viewholder:
itemView.setVisibility(View.GONE);
or each element:
view.setVisibility(View.GONE);
But don't forget to set them VISIBLE otherwise, you will end up with some strange things from recycling
IF
view.setVisibility(View.GONE);
gives you a Blank view
Then follow This.
public static class Data_ViewHolder extends RecyclerView.ViewHolder {
private final LinearLayout layout;
final LinearLayout.LayoutParams params;
public Show_Chat_ViewHolder(final View itemView) {
super(itemView);
.
.
.
layout =(LinearLayout)itemView.findViewById(R.id.show_item_layout);
params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
.
.
.
}
private void Layout_hide() {
params.height = 0;
//itemView.setLayoutParams(params); //This One.
layout.setLayoutParams(params); //Or This one.
}
}
Now Call from Adapter
mFirebaseAdapter = new FirebaseRecyclerAdapte......{
public void populateViewHolder.....{
if(model.getData().equals("..Something.."))
{
viewHolder.Layout_hide();
}
else
viewHolder.Person_Email(model.getEmail());
}
}
If you are hiding whole itemView and facing the problem of blank spaces.
Try this to hide the itemView.
holder.itemView.setVisibility(View.GONE);
ViewGroup.LayoutParams params = holder.itemView.getLayoutParams();
params.height = 0;
params.width = 0;
holder.itemView.setLayoutParams(params);
And this to show it.
holder.itemView.setVisibility(View.VISIBLE);
This is a recyclerView, so use both in if else block or you might encounter some unintended UI issues.
There is no built in way to hide a child in RecyclerView.
But you can implement this feature in your Adapter.
public class MyAdapter extends RecyclerView.Adapter<...>{
List<Object> items;
Map<Integer,Object> deletedItems;
...
public void hideItem(final int position) {
deletedItems.add(position, items.get(position));
items.remove(position);
notifyItemRemoved(position);
}
....
}
"GONE" will not remove the space occupied by the item ....you can use
if (condition) {
item.layoutParams.height = 0
item.layoutParams.width = 0
}
inside "onBindViewHolder"
public class OfferViewHolder extends RecyclerView.ViewHolder {
public TextView textViewOfferName;
public LabelImageView labelImageView;
public TextView textViewOldPrice;
public TextView textViewNewPrice;
public TextView textViewShopName;
public TextView textViewTimeDate;
public TextView textViewDistance;
public LinearLayout linearLayoutMain;
public OfferViewHolder(View view) {
super(view);
linearLayoutMain=(LinearLayout) view.findViewById(R.id.ll_main);
textViewOfferName = (TextView) view.findViewById(R.id.textViewoffername);
labelImageView=(LabelImageView) view.findViewById(R.id.labelImageView) ;
textViewOldPrice=(TextView) view.findViewById(R.id.textViewOldPrice);
textViewNewPrice=(TextView) view.findViewById(R.id.textViewNewPrice);
textViewShopName=(TextView) view.findViewById(R.id.textViewShopName);
textViewTimeDate=(TextView) view.findViewById(R.id.textViewDate);
textViewDistance=(TextView) view.findViewById(R.id.textViewDistance);
linearLayoutMain.setVisibility(View.GONE);
textViewOfferName.setVisibility(View.GONE);
labelImageView.setVisibility(View.GONE);
textViewOldPrice.setVisibility(View.GONE);
textViewNewPrice.setVisibility(View.GONE);
textViewShopName.setVisibility(View.GONE);
textViewTimeDate.setVisibility(View.GONE);
textViewDistance.setVisibility(View.GONE);
}
}`enter code here`
THEN IN YOUR ADAPTER
if (a.equals(offer.getOfferCategory())) {
if (offer.getOfferCategory()==null){
// chatMessageViewHolder.getLinearLayoutMain().setVisibility(View.GONE);
// chatMessageViewHolder.linearLayoutMain.setLayoutParams(new RecyclerView.LayoutParams(0, 0));
}
else {
chatMessageViewHolder.itemView.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewShopName.setText(offer.getOfferCategory());
chatMessageViewHolder.linearLayoutMain.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewOfferName.setVisibility(View.VISIBLE);
chatMessageViewHolder.labelImageView.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewOldPrice.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewNewPrice.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewShopName.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewTimeDate.setVisibility(View.VISIBLE);
chatMessageViewHolder.textViewDistance.setVisibility(View.VISIBLE);
}
Thank you lorescu George Cătălin and Dhalav
holder.itemView.setVisibility(View.VISIBLE); is not working now. I am using this
holder.itemView.findViewById(R.id.card).setVisibility(View.GONE);
you can easily send the ViewHolder value to your action function ..
I do not recommend answers with setting height and width of View to 0 because adapter still needs to render them and if there are too many hidden items this can cause lags, it is better to change the list itself and then send it to the adapter
It seems like RV internally caches root view info so changing it's visibility does nothing to occuppied space by the item.
Wrap you RV item view with FrameLayout and set View.GONE to inner view. This way occupped space will be cleared correctly as well as item won't be shown at all.
private fun hideShowItemView(itemView: View, toShow: Boolean) {
itemView.isVisible = toShow
itemView.layoutParams.height = if (toShow) ViewGroup.LayoutParams.WRAP_CONTENT else 0
}
itemView is an ItemView of the ViewHolder
toShow is a boolean to hide or show item of recyclerview
Use below line of code in onBindViewHolder block as per the requirement,
To hide Item : hideShowItemView(holder.itemView, false)
To show Item : hideShowItemView(holder.itemView, true)

Hiding views in RecyclerView

I have code like this
public static class MyViewHolder extends RecyclerView.ViewHolder {
#InjectView(R.id.text)
TextView label;
public MyViewHolder(View itemView) {
super(itemView);
ButterKnife.inject(this, itemView);
}
public void hide(boolean hide) {
label.setVisibility(hide ? View.GONE : View.VISIBLE);
}
}
which maps to a single row in a RecyclerView. R.id.text is in fact the root view of the layout that gets inflated and passed in to the constructor here.
I'm using the default implementation of LinearLayoutManager.
In bindViewHolder, I call hide(true) on an instance of MyViewHolder, but instead of collapsing the row as expected, the row becomes invisible, maintaining its height and position in the RecyclerView. Has anyone else run into this issue?
How do you hide items in a RecyclerView?
There is no built in way to hide a child in RV but of course if its height becomes 0, it won't be visible :). I assume your root layout does have some min height (or exact height) that makes it still take space even though it is GONE.
Also, if you want to remove a view, remove it from the adapter, don't hide it. Is there a reason why you want to hide instead of remove ?
Put method setVisibility(boolean isVisible) in ViewHolder.
You can change itemView params(width and height) for LayoutManager:
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
...
public void setVisibility(boolean isVisible){
RecyclerView.LayoutParams param = (RecyclerView.LayoutParams)itemView.getLayoutParams();
if (isVisible){
param.height = LinearLayout.LayoutParams.WRAP_CONTENT;
param.width = LinearLayout.LayoutParams.MATCH_PARENT;
itemView.setVisibility(View.VISIBLE);
}else{
itemView.setVisibility(View.GONE);
param.height = 0;
param.width = 0;
}
itemView.setLayoutParams(param);
}
public ViewHolder(View itemView) {
super(itemView);
...
}
}
and change visibility for ItemDecoration (Divider):
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
...
#Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
...
for (int i = 0; i < parent.getChildCount(); i++) {
if (parent.getChildAt(i).getVisibility() == View.GONE)
continue;
/* draw dividers */
}
}
}
You CAN do it!
First, you need to detect which position of item that you want to hide. You can custom getItemViewType to do it.
Next, on onCreateViewHolder, depend on the view type. You can do something like this:
if(viewType == TYPE_HIDE) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.empty_item, parent, false);
vHolder = new ViewHolder(context, v, viewType, this);
break;
}
return vHolder;
-> empty item is a layout that have nothing, (in other word, it is default layout whenever created). or code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
Hope it help!
Okay, so the way I did it in the end was I had my whole dataset, say, myObjects and I had scenarios where I would only want to show subsets of that dataset.
Since setting visibility of rows in RecyclerView doesn't cause the heights to collapse, and setting the heights of the rows did not appear to do anything either, what I had to do was just keep a secondary dataset called myObjectsShown which was nothing more than a List<Integer> that would index into myObjects to determine which objects would be displayed.
I would then intermittently update myObjectsShown to contain the correct indices.
Therefore,
public int getItemCount() {
return myObjectsShown.size();
}
and
public void onBindViewHolder(MyViewHolder holder, int position) {
Object myObject = myObjects.get(myObjectsShown.get(position));
// bind object to viewholder here...
}
For hiding view in RecyclerView I hide/show view in OnBindViewHolder:
if (item.isShown) {
vh.FooterLayout.setVisibility(View.Visible);
} else {
vh.FooterLayout.setVisibility(View.Gone);
}
And for example - from activity I simply redraw needed item:
_postListAdapter.notifyItemChanged(position)// if you want show/hide footer - position is amountOfPosts.size() and also change bool variable - amountOfPosts[amountOfPosts.size()].isShown
For the sake of completeness, you should note that setting view visibility to GONE would not hide the margins. You need to do something like this :
if(itemView.getVisibility() != GONE) itemView.setVisibility(GONE);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) itemView.getLayoutParams();
layoutParams.setMargins(0, 0, 0, 0);
itemView.setLayoutParams(layoutParams);

Android ExpandableListView using animation

I'm using
<ExpandableListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ExpandableListView>
i want add animation slide for child when onclick parent . So How can i do ?
Final Update
It's been quite a while since I wrote this answer. Since then a lot has changed. The biggest change is with the introduction of RecyclerView that makes animating a list or grid easy. I highly recommend switching over to RecyclerViews if you can. For those who can't I will see what I can do regarding fixing the bugs for my library.
Original answer
I actually do not like the popular implementation of an animated ExpandableListView that simply uses a ListView with an expand animation because in my use case, each of my groups had a lot of children, therefore it was not feasible to use a normal ListView as the child views will not be recycled and the memory usage will be huge with poor performance. Instead, I went with a much more difficult but more scalable and flexible approach.
I extended the ExpandableListView class and overrode the onCollapse and onExpand functions, I also created a subclass of a BaseExpandableListAdapter called AnimatedExpandableListAdapter. Inside the adapter, I overrode the getChildView function and made the function final so that the function cannot be overrode again. Instead I provided another function called getRealChildView for subclasses to override to provide a real child view. I then added an animation flag to the class and made getChildView return a dummy view if the animation flag was set and the real view if the flag was not set. Now with the stage set I do the following for onExpand:
Set the animation flag in the adapter and tell the adapter which group is expanding.
Call notifyDataSetChanged() (forces the adapter to call getChildView() for all views on screen).
The adapter (in animation mode) will then create a dummy view for the expanding group that has initial height 0. The adapter will then get the real child views and pass these views to the dummy view.
The dummy view will then start to draw the real child views within it's own onDraw() function.
The adapter will kick off an animation loop that will expand the dummy view until it is of the right size. It will also set an animation listener so that it can clear the animation flag once the animation completes and will call notifyDataSetChanged() as well.
Finally with all of this done, I was able to not only get the desired animation effect but also the desired performance as this method will work with group with over 100 children.
For the collapsing animation, a little more work needs to be done to get this all setup and running. In particular, when you override onCollapse, you do not want to call the parent's function as it will collapse the group immediately leaving you no chance to play an animation. Instead you want to call super.onCollapse at the end of the collapse animation.
UPDATE:
I spent some time this weekend to rewrite my implementation of this AnimatedExpandableListView and I'm releasing the source with an example usage here:
https://github.com/idunnololz/AnimatedExpandableListView/
animateLayoutChanges adds auto-animation
<ExpandableListView
android:animateLayoutChanges="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
#idunnololz solution works great. however i would like to add some code to collapse previously expanded group.
private int previousGroup=-1;
listView.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
// We call collapseGroupWithAnimation(int) and
// expandGroupWithAnimation(int) to animate group
// expansion/collapse.
if (listView.isGroupExpanded(groupPosition)) {
listView.collapseGroupWithAnimation(groupPosition);
previousGroup=-1;
} else {
listView.expandGroupWithAnimation(groupPosition);
if(previousGroup!=-1){
listView.collapseGroupWithAnimation(previousGroup);
}
previousGroup=groupPosition;
}
return true;
}
});
#idunnololz solution is working great, but I experienced weird behavior with my custom layout for group. The expand operation was not executed properly, the collapse however worked perfect. I imported his test project and it worked just fine, so I realized the problem is with my custom layout. However when I was not able to locate the problem after some investigation, I decided to uncomment these lines of code in his AnimatedExpandListView:
if (lastGroup && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return expandGroup(groupPos, true);
}
which caused the problem (my app is aimed for Android 4.0+).
Found this snnipet not remebering where here in Stack Overflow. Have two basic static methods: expand(View v) and collapse(View v).
You only have to pass the view you want to hide show.
Note: I Don't recomend pass a view having wrap_content as height. May not work fine.
public class expand {
public static void expand(View view) {
view.setVisibility(View.VISIBLE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(widthSpec, heightSpec);
ValueAnimator mAnimator = slideAnimator(view, 0, view.getMeasuredHeight());
mAnimator.start();
}
public static void collapse(final View view) {
int finalHeight = view.getHeight();
ValueAnimator mAnimator = slideAnimator(view, finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animator) {
view.setVisibility(View.GONE);
}
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
mAnimator.start();
}
private static ValueAnimator slideAnimator(final View v, int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.height = value;
v.setLayoutParams(layoutParams);
}
});
return animator;
}
}

Android: Animation in Gallery View?

When I use the Gallery widget, how do I get the images to say scale up & glow on being selected and scaled down & un-glow on being unselected?
All tutorials I've seen have this effect but I'm not able to see it...
Is there some kind of an animation that I have to attach to the Gallery?
Hope this is helpful. I manage to "simulate" the shrink/grow solution with the Gallery widget. Since they removed the getScale(), things get a little bit complicated. I think that this it's not the best solution at all, but at least I can live with it.
What I have found is that Gallery manages the focus EXTREMELY BAD. So, the first approach was to add a focus change listener on the ImageView displayed, but no luck there. Focus is a MESS there... in terms that, the selected image it's not the currently focused view. I have sent a mail to android-developers mailing list about some error on API doc (regarding the focusSearch()method and some focus contants).
Here's my solution to this problem:
Build an animation resource to 'grow' the image:
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="1.0"
android:toXScale="1.10"
android:fromYScale="1.0"
android:toYScale="1.10"
android:duration="300"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:fillAfter="false"/>
If you don't get what that means then you should proceed to read this
That will be our 'grow' effect, and you will need to save it in: res/anim/grow.xml or whatever name it suites you (but always in res/anim dir).
You can follow the resource guide from here to create a Gallery view. The ImageAdapter builds an ImageView every time that the Gallery object calls getView(). One workaround you could implement is adding a line to the getView() method that identifies a View with a position, this way:
...
i.setId(position);
...
With that line added to the getView() method of the ImageAdpater object, you can then unequivocally identify that view within a listener, for instance:
g.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected (AdapterView<?> parent, View v, int position, long id) {
Animation grow = AnimationUtils.loadAnimation(YourActivity.this, R.anim.grow);
View sideView = parent.findViewById(position - 1);
if (sideView != null)
((ImageView)sideView).setLayoutParams(new Gallery.LayoutParams(150, 100));
sideView = parent.findViewById(position + 1);
if (sideView != null)
((ImageView)sideView).setLayoutParams(new Gallery.LayoutParams(150, 100));
v.startAnimation(grow);
v.setLayoutParams(new Gallery.LayoutParams(170, 150));
}
public void onNothingSelected (AdapterView<?> parent) {
System.out.println("NOTHING SELECTED");
}
});
NOTE: You may notice that all the values from animation and from layout parameters has been choosen by me at hand. This is because i'm not going to clean code for you. And, this is just a workaround the BAD focus issue with this widget or the android view system. If focus were OK, then, all you need to do is set a focus change listener that makes the gros/shrink when it got focus/unfocused.
I hope this may help you to find a way around for your problem,
Regards,
New EDIT: This is the listener I have set, I also added the line i.clearAnimation() in the getView() method:
private class SelectListener implements AdapterView.OnItemSelectedListener {
private Animation grow;
private int last;
public SelectListener() {
grow = AnimationUtils.loadAnimation(RouteGallery.this, R.anim.grow);
last = 0;
}
public void onItemSelected (AdapterView<?> parent, View v, int position, long id) {
View sideView = parent.findViewById(last);
if (sideView != null && last != position)
sideView.clearAnimation();
v.startAnimation(grow);
last = position;
}
public void onNothingSelected (AdapterView<?> parent) {
}
}
You need to use an ImageSwitcher. The ImageSwitcher has methods for setting the in and out animations (when image is selected and deselected, or selected and replaced).
The following link has a good tutorial on how to use it in conjunction with the Gallery.
I implemented a similar animation like this:
final Animation shrink = AnimationUtils.loadAnimation(activity, R.anim.shrink);
shrink.setFillAfter(true);
gallery.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// This iterates through the views which are currently displayed on screen.
for (int k=0; k<gallery.getChildCount(); k++){
// Do whatever else you want, here.
// This is how you get a particular element of a view
ImageView background = (ImageView) gallery.getChildAt(k).findViewById(R.id.menu_item_background);
//clear animation
gallery.getChildAt(k).clearAnimation();
}
// Scale the selected one
view.startAnimation(shrink);
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {}
});

Categories

Resources