Custom animation for ExpandableListView Child - android

I wanna use a custom animation (slide down/up) for childs in an ExpandableListView. So if I click on element #2, I want the child of parent element #2 to expand using the animation. And withdraw / close, when I click the parent again.
However, I do have problems directing the animation at the child itself. The closest I can get, is to animate the parent, by using "myListView.getChildAt(groupPosition).setAnimation(slide_down);" as seen below.
When I use this pierce of code and I click element x, then element x will makes an animation - But it's the child who should make the animation, not the clicked parent.
My code in MainActivity, where "myAdapter" is the adapter and "myListView" is the ExpandableListView:
ExpandableListAdapter myAdapter = new ExpandableListAdapter(context, arrRO);
final ExpandableListView myListView = (ExpandableListView) findViewById(R.id.reminderlistView);
myListView.setAdapter(myAdapter);
myListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
if (myListView.isGroupExpanded(groupPosition)) {
//Need to implement collapsing animation as well
myListView.collapseGroup(groupPosition);
} else {
boolean autoScrollToExpandedGroup = false;
myListView.expandGroup(groupPosition, autoScrollToExpandedGroup);
setupLayoutAnimation(groupPosition);
//
}
//telling the listView we have handled the group click, and don't want the default actions.
return true;
}
private void setupLayoutAnimation(int groupPosition) {
Animation slide_down = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down);
myListView.getChildAt(groupPosition).setAnimation(slide_down);
//myListView.setAnimation(slide_down);
}
I also included the "myListView.setAnimation(slide_down);", but if I use that and click on an element, every single displayed element (parents + children) make this little animation, and I only want it for the child.
There will always only be 1 child, for every parent, if that makes any difference.

ExpandableListView is not very flexible. You are probably better off creating a custom view where you can control how the children of a group are displayed when the group is clicked.
There is a bit more work to get your custom view in place, but it'll aford you much more flexibility that an ExpandableListView can.
You'll need 2 new views, a Parent view, and a child view. The Parent view will inherit from one of the ViewGroups (use LinearLayout or FrameLayout as you have a single child), while the childView will be based on what you want to display, it could be a TextView or some ViewGroup with a few child views. When you detect a click on the Parent, you would animate the child it contains, and you could pass that click event up the chain using an interface if needed.

Related

Android how to get an ancestor view from a child view?

I have a list of type Foo with a custom array Adapter. I want to be able to click on a child element in one of the views in the array adapter and get back the view I clicked on of type Foo.
This is how I am clicking on a child element:
// fill array with a test set of objects
final ArrayList<Foo> locations = Foo.getTestingList();
final myCustomArrayAdapter adapter = new myCustomArrayAdapter(rootView.getContext(), myarrayList);
adapter.setDefaultRequestBtnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
//if child element is clicked
if(v.getId() == R.id.deleteBTN){
//tag is set to the position in my custom adapter
int pos = (Integer)v.getTag();
//Get this child's parent view (type foo)
}
}
});
I want to be able to use certain Foo methods on the Fooparent of the child View I just clicked on.
If you wanna get the direct parent of a view, you can call the method getParent() and it will return immediate parent of the target view. Note, this method doesn't directly return a view but instead a ViewParent. ViewParent does not technically need to be a View but all views capable of holding child views i.e. a "view parent" in the Android SDK are of type ViewGroup which itself implements the ViewParent. So in reality virtually all ViewParents are a ViewGroup, which in itself is a View.
Furthermore, if you wanna access an ancestor view that's beyond the direct parent, you can recursively call getParent() and perform checks on the return parent view to determine if they are the desired view.

expand all view when activity is load in ExpandableListView

My problem is...
I use Expandable list view in my activity.
When the activity created it shows all the child group is collapsed.
I would like to expand all children while the expandable list view is populated.
like
for that, I used below code in getGroupView() method adapter class
ExpandableListView eLV = (ExpandableListView) parent
eLV.expandGroup(groupPosition,true);
now the groups are expanded but it can not allow me to collapse by clicking on the group header.
Simply add groupClickListener and return true for disabling collapse the child list. Add this code to your activity.
yourExpandableList.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
return true; // This way the expander cannot be collapsed
}
});

ExpandableListView child views positioning on group expand or scroll

I'm working on implementing an ExpandableListView with my custom Adapter that extends BaseExpandableAdapter .
Working with the MVP model i successfully inflate all the groups and views in the right way. Piece of my GetChildView()
public override View GetChildView(int groupPosition, int childPosition, bool isLastChild, View convertView, ViewGroup parent)
{
BetViewHolder holder = new BetViewHolder(_BetPresenter);
var view = convertView;
if (view != null)
holder = view.Tag as BetViewHolder;
else
{
LayoutInflater layoutInflater = (LayoutInflater)_Context
.GetSystemService(Context.LayoutInflaterService);
holder = new BetViewHolder(_BetPresenter);
view = layoutInflater.Inflate(Resource.Layout.live_bet_view_item, null);
holder.InitEventViews(view);
view.Tag = holder;
}
_BetPresenter.OnBindBetEventView(holder, groupPosition, childPosition);
return view;
}
Inside the presenter at OnBindBetEventView i set the data on the corresponding view.
The problem
Each child item has a 3 custom components(Buttons) which are selectable. And in general each child view is relatively complex. When i select one of the buttons of the child view it successfully changes the color like it should, but also other child views from other groups change get selected too. The strange part comes when i scroll or collapse/expand a group.
The selected views are changing and some others are getting selected instead. 'Playing' with the groups it messes the all the selected buttons without a specific pattern.
Clicking the first button also checks another button on another group. It was not already selected by me. Scrolling and expanding groups changes the order of selected buttons
NOTE
After lots of debugging i realized that every 2 buttons the Unique view id's of the buttons are duplicate. Meaning that the instance of the view is exactly the same. Maybe is due to recycling or something. The point is that i need to preserve the state of my selected views without letting the adapted change the position of my views.
The recycling mechanism of the ExpandableList was causing this strange behavior due to the reuse-ability of the views. The ChildView with the clicked item was recycled once it was out of screen and inflating it again on a different position
I realize that due to the fact that the views had exactly the same unique hash created by Android. There was a duplication
I solved it by checking my model's state everytime the adapter tries to inflate the view, on the position it tries to inflate it.
Here is the ViewHolder method called from the adapter at GetChildView()
public void SetEventToView(Event eventItem)
{
txtCompetitor1.Text = eventItem.Competitor1;
txtCompetitor2.Text = eventItem.Competitor2;
txtTime.Text = eventItem.Time;
txtScore.Text = eventItem.Score;
for (int i = 0; i < _OddButtonList.Count; i++)
{
_OddButtonList[i].OddID = eventItem.BetItems[i].ID;
_OddButtonList[i].SetPriceText(eventItem.BetItems[i].BetOdd);
_OddButtonList[i].SetOnClickListener(this);
SetButtonState(eventItem, _OddButtonList[i], i);
}
}

Two items get selected in listview android

I'm trying to implement a custom listview. Everything works fine until I use a if () statement inside the getView() method
Without the if() condition a single item gets selected when I select an item but when I add the if() condition, the views are displayed properly but two items (non-adjacent) get selected (1st and last 1st or and second-last, any such combination).
View getView(...){
....
if (!item.getPriceTo().equals(""))
priceToTV.setText(item.getPriceTo());
else
priceToTV.setText(item.getPriceFrom());
return view;
}
Also I'm using saving the previous view to show the selection so the current selection has a red_border and when it is selected a black_border is set to it.:
subItemsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Log.d("New Order", "........");
if (previousViewOfSubItems != null && previousViewOfSubItems != view) {
previousViewOfSubItems.setBackgroundResource(R.drawable.black_border);
if (quantity.getText().toString().equals("xx") || quantity.getText().toString().equals("0")) {
viewForVisibility.setVisibility(View.GONE);
layoutForQuantity.setVisibility(View.GONE);
}
}
if (previousViewOfSubItems == view)
return;
previousViewOfSubItems = view;
previousViewOfSubItems.setBackgroundResource(R.drawable.red_border);
viewForVisibility = previousViewOfSubItems.findViewById(R.id.viewForVisibility);
viewForVisibility.setVisibility(View.VISIBLE);
layoutForQuantity = (LinearLayout) previousViewOfSubItems.findViewById(R.id.layoutForQuantity);
layoutForQuantity.setVisibility(View.VISIBLE);
quantity = (TextView) previousViewOfSubItems.findViewById(R.id.subTypeQuantity);
}
});
previousViewOfSubItems = view; seems to be causing the problem,
In Listviews with adapter you should avoid saving view instances, because views are reused by adapters so view can be same for two rows so rather than saving view instance's reference use ViewHolder Design pattern and use view tagging
You need to use ViewHolder Pattern and view tagging to properly identify every view in different position. ListView always recycle the view instead of re-inflating the view again and again.
You can refer to Android Training documentation on how to implement ViewHolder pattern.
ListViews recycle the views in the list. so as you scroll, top views are reused and content replaced using the methods.
Where you set background to Red etc, use Else statements to set it back to your default black.
its beacause it listview reuses view to display items, once the first view is scrolled out the the same view is reused to display the view at bottom of the listview. instead of comparing the view try compairing the position of the view clicked
I have explained about this abnormal behavior in my blog on recyclerview you refer that to solve this problem.
use pojo class to get the status and update the view accordingly

Button In the Footer of ListView View Does Not Receive Events after the ListView is scrolled

I have a listview with each row containg a check box and text. I have successfully added an "Answer" button to the footer of the list view that recives events and puts up a toast message saying You Clicked the save button. The problem is if the list view is scrollable and I scroll the list view up and down a couple of times, the Answer button in the footed is no longer active (at least in the emulator). The behavior seems to be that the button does not respond to any events at all. However, checking/unchecking the check box in the list view item will cause the setOnClickListener event of the Answer button to fire.
View footer = View.inflate(this,R.layout.footer, null);
getListView().addFooterView(footer,null, true);
Button btnAnswer = (Button)footer.findViewById(R.id.btnAnswer);
btnAnswer.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Toast.makeText(getApplicationContext()," You clicked Save button", Toast.LENGTH_SHORT).show();
}
});
ListViews "re-use" child views for each list item to save on memory consumption, time, etc instead of recreating new views for each item. You're setting the OnClickListener; however, when you scroll around the footer view is getting repurposed for another list item and therefore the OnClickListener is invalid.
You'll need to extend your ListAdapter and override the getView method in which you'll want to check for the footer view and set the appropriate listener if it is.
Something like:
setListAdapter(new ArrayAdapter<string>(this, R.layout.list_item, strings) {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Unless you want to set each child views individually, call
// the super
convertView = super.getView(position, convertView, parent);
// Check if it's the footer view
if(position == this.getCount() - 1) {
// Set the listener here
}
return convertView;
}
});
your button is competing for focus with the listview... listview is winning... each view (listview and your button) are fighting for focus since they have the same type of listener .... you'll have to switch to setOnTouchListener for the button to get it to work and use onClickListener for the listview
for example using anonymous class:
yourfooterButton.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
//your response code
}
}
});
There is one more alternative and its to set the following on the footer. There is another method overload created but it did not come up in the docs, i had to check online documentation:
mylistView.addFooterView(footerView, null, **false**);
where false tells the footer its not selectable. I tested this myself and the buttons inside the footer respond to touches now. I hope this an acceptable answer.

Categories

Resources