I am trying to imlpement some animation to be played every time that I expand a group of an ExpandableListView. So far I do the following the getChildView of my custom adapter (based on BaseExpandableListAdapter):
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view,
ViewGroup parent) {
// Auto-generated method stub
ExpandListChild child = (ExpandListChild) getChild(groupPosition,childPosition);
if (view == null)
{
LayoutInflater inflater =
(LayoutInflater) m_context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view=inflater.inflate(R.layout.expandlist_child_item, null);
AnimatorSet anim = (AnimatorSet) AnimatorInflater.loadAnimator(m_context,
R.animator.expand_list_animation);
anim.setInterpolator(new OvershootInterpolator());
anim.start();
}
TextView tv = (TextView) view.findViewById(R.id.tvChild);
tv.setText(child.getName());
tv.setTag(child.getTag());
CheckBox cb = (CheckBox) view.findViewById(R.id.checkBox1);
cb.setChecked(child.getState());
return view;
}
The problem is that because I am applying the animation only when creating a new view, this only works the first time that the group is expanded. I also tried to apply it in any case (not only when view==null) but the problem is that the animation is played for all expanded children (even those of other groups that are already expanded).
I have been trying a lot to get this to work and I cannot figure out how. Your help is appreciated.
Related
I have a very strange problem in my navigation drawer.
I want to implement the navigation drawer like the one the Google Play Store has.
I've implement my navigation drawer in a base adapter but when I run my app in a emulator everythings looks fine when I open the navigation drawer, but when I click a item suddenly all items are mixed up(only on my android 2.3 device) The other one i;ve tested is a 4.4.2 Android device and everything works fine!
Code
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(ActionBarActivity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.drawer_list_item, null);
}
if (convertView != null) {
//i//f(!(navDrawerItems.get(position).IsLoaded())) {
//navDrawerItems.get(position).SetLoaded();
ImageView imgIcon = (ImageView) convertView.findViewById(R.id.icon);
TextView txtTitle = (TextView) convertView.findViewById(R.id.title);
TextView txtCount = (TextView) convertView.findViewById(R.id.counter);
if (navDrawerItems.get(position).getIconVisibility()) {
imgIcon.setImageResource(navDrawerItems.get(position).getIcon());
txtTitle.setTextSize(20);
//txtTitle.setMinHeight(20);
LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
llp.setMargins(8, 0, 0, 0); // llp.setMargins(left, top, right, bottom);
llp.height = 60;
txtTitle.setLayoutParams(llp);
convertView.setBackgroundResource(R.drawable.nav_little_border);
} else {
imgIcon.setVisibility(View.GONE);
}
txtTitle.setText(navDrawerItems.get(position).getTitle());
// displaying count
// check whether it set visible or not
if (navDrawerItems.get(position).getCounterVisibility()) {
txtCount.setText(navDrawerItems.get(position).getCount());
} else {
// hide the counter view
txtCount.setVisibility(View.GONE);
}
// }
}
I only want to show the icons for the last 2 items like (http://www.androidcentral.com/sites/androidcentral.com/files/styles/large_wm_brw/public/article_images/2014/04/Play-Movies-TV-sidebar.jpg?itok=qLSLoPNp)
this is the code in my custom adapter (THE CODE IN BROWN COLOR) when initially list is build proper margin is applied to valid items when i scroll down and again scroll up all the rows in list shifts the margin left by 20 what i'm doing wrong please reply soon
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
// getting data
final ViewMovieDetailsModel_ViewComments movies = getItem(position);
if (convertView == null)
{
convertView = View.inflate(context, R.layout.comment_row, null);
holder = new ViewHolder();
//getting handles
holder.comments_linearLayout = (LinearLayout) convertView.findViewById(R.id.comments_linearLayout);
holder.commenter_textView = (TextView) convertView.findViewById(R.id.comment_row_commenter);
holder.commented_on_textView = (TextView) convertView.findViewById(R.id.comment_row_comment_time);
holder.comment_text_textView = (TextView) convertView.findViewById(R.id.comment_row_comment_text);
holder.reply_button = (Button) convertView.findViewById(R.id.comment_row_reply_button);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
if (movies != null)
{
if (((movies.getParent_comment_id()).toString().equals("null")) && session.isLoggedIn()==true) {
holder.reply_button.setVisibility(View.VISIBLE);
}else{
holder.reply_button.setVisibility(View.INVISIBLE);
}
`if (!((movies.getParent_comment_id()).toString().equals("null")))
{
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT);
params.setMargins(20, 0, 0, 0);
holder.comments_linearLayout.setLayoutParams(params);
}`
holder.commenter_textView.setText(movies.getUsername_commentor());
holder.commenter_textView.setTag(movies.getUser_id_commentor());
return convertView;
}
because you are setting margins (the brown font) in 'if' statement:
if (movies != null)
just take it out of this if block (for example put it just before the return point)
Right now this code is probably not executed at the first view load, since the movie is null. When the getView is called second time, the movie is not null, and the marigin is set according to your 'brown' code.
if this is not the solution - maybe the inside if statement condition is not true (the one that is in first 'brown' row). so.. your own logic prevents the marigins to be set as you want :)
Please let me know if it helps.
One way you could go about solving this problem is instead of using LayoutParams.setMargins(20, 0, 0, 0), you could create an empty TextView whose width is 20 dp by default and whose position will be to the left of your rows contents. It will be View.GONE by default, but when if (!((movies.getParent_comment_id()).toString().equals("null"))) happens, you can set that to View.VISIBLE
I've got and ExpandableList which I assign to an extended BaseExpandableListAdapter. In here, I implement the getChildView method to setup and return a View for each child:
public View getChildView(int groupIndex, int childIndex, boolean isLastChild, View convertView, ViewGroup parent) {
LinearLayout layout;
if (convertView == null) {
layout = (LinearLayout) LayoutInflater.from(MyApp.getContext()).inflate(R.layout.rooms_room_list_row, parent, false);
} else {
layout = (LinearLayout) convertView;
}
// Do some custom stuff with views on the layout
...
return layout;
}
While debugging, I've noticed that getChildView is executed twice per child. All the values passed in (i.e, groupIndex, childIndex, isLastChild) are the same... so in group 3, if I've got two children, I'll see:
groupIndex = 3, childIndex = 0
then
groupIndex = 3, childIndex = 1
then it repeats:
groupIndex = 3, childIndex = 0
and finally:
groupIndex = 3, childIndex = 1
My view appears fine, i.e, there are only two children listed for the group, but why is it doing all the extra work?
UPDATE & ANSWER
It seems that if the the listview is set to a height of wrap_content then the getChildView will be called twice per child. Changing the height to fill_parent seems to fix this behavior.
As I mentioned in your other question, the ListView calls getView() to get the dimensions (width and height) of some items first, then calls the getView() again to actually render the items. Check this video out, it's "required reading" for Android. The bit that deals with your question is at minute 41:30.
I'm working on an Android app that utilizes a ListView, in which each row is comprised of a text view and a progress bar. Things work smoothly unless the user has to scroll through a long list.
ProgressBars start taking on the progress of other ProgressBars not currently visible on the screen.
I understand that this is a common issue that stems from the implementation of GetView, but I'm wondering what the best course of action is to take with ProgressBars.
GetView:
public View getView(int position, View convertView, ViewGroup parent){
View row = convertView;
ViewWrapper wrapper;
ProgressBar myProgressBar;
int initProgress = myData.get(position).getProgress();
if (row == null){
LayoutInflater inflater = context.getLayoutInflater();
row = inflater.inflate(R.layout.row, null);
wrapper = new ViewWrapper(row);
row.setTag(wrapper);
}
else{
wrapper = (ViewWrapper)row.getTag();
}
RowModel model = getModel(position);
wrapper.getPid().setText(model.toString());
myProgressBar = wrapper.getProgressBar();
myProgressBar.setProgress(initProgress);
myProgressBar.setMax(100);
myProgressBar.setTag(new Integer(position));
return row;
}
ViewWrapper:
public class ViewWrapper {
View base;
TextView pid = null;
ProgressBar pb= null;
ViewWrapper(View base){
this.base = base;
}
TextView getPid(){
if(pid == null){
pid = (TextView)base.findViewById(R.id.pid);
}
return(pid);
}
ProgressBar getProgressBar(){
if(pb== null){
pb= (ProgressBar)base.findViewById(R.id.progressbar);
}
return(pb);
}
}
It seems that the issue is related to:
myProgressBar = wrapper.getProgressBar();
because that ProgressBar starts getting the behavior of a recycled ProgressBar. However, I want it to have its own behavior.
What's the best way to alleviate this? Thanks.
You may need to inflate the layout each time and not re-use the convertView that's passed in. This shouldn't be a problem unless you have A LOT of rows.
I had to implement a similar feature , here is what I did . I implemented the following outside getview
OnTouchListener - to listen to seekbar touch events
OnKeyListener - to listen to dpad and trakball event for the seekbar
I set these listeners for the seekbars from getView
Whenever the listeners were called , I would find the seekbars parent , then do the findviewbyid from the parent to the textview.
So now I have the textview which I have to update, and the seekbar. All I need to do was set the text from the array.
here is some code to help you.
private OnTouchListener touchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
View parent = (View) v.getParent();
TextView textView = (TextView) parent
.findViewById(R.id.id_grade_tooltip);
if (textView == null) {
} else {
SeekBar seekBar = (SeekBar) v;
textView.setText(String.valueOf(seekBar.getProgress())
+ "%");
}
return false;
}
};
I'm working on an extension of BaseExpandableListAdapter, and have the following implementation of getChildView():
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent)
{
AbsListView.LayoutParams lp = new AbsListView.LayoutParams
(ViewGroup.LayoutParams.FILL_PARENT, 48);
RelativeLayout layout = new RelativeLayout(myExpandableListActivity.this);
layout.setLayoutParams(lp);
TextView name = new TextView(myExpandableListActivity.this);
name.setText("testing...");
layout.addView(name);
return layout;
}
This code is working, and when I run the application, expand a group and click on a child, the parent application is able to detect onChildClick() correctly.
However, I notice that the onChildClick() does not work anymore if I don't call the setLayoutParms(). My question is, what is happening when I assign AbsListView.LayoutParams to the child view being returned? Why is this required to have my onChildClick() respond in the parent application?
Thanks in advance!
After playing with other parts of the code some more, it looks like leaving out setLayoutParms() was not what was causing my onChildClick() to not work. I was also using a layout inflater to set up my RelativeLayout, which included a CheckBox. Turns out it was the CheckBox that was causing the child to be unclickable, something that I'll have to look into further.
RelativeLayout spellLayout = (RelativeLayout)
getLayoutInflater().inflate(R.layout.testLayout, null);
Thanks for reading!