2015-04-01 22 views
3

我試圖做的是在點擊時製作一個Viewshake,再次單擊時停止晃動,我做了它,但是當我滾動GridView時, ,以及另一個未被點擊的View上的動畫動畫。GridView上的動畫在滾動上搞砸了

這裏有一個更清楚的解釋:http://i.imgur.com/IDv7vJ6.gif

我不知道爲什麼這些人的觀點都在抖。

這裏是我的代碼:

public class PeopleFragmentGridAdapter extends BaseAdapter { 

private List<Person> people = new ArrayList<>(); 
private Context context; 
private Map<Integer, Boolean> animating; 
private Map<Integer, ObjectAnimator> animators; 

public PeopleFragmentGridAdapter(Context context, List<Person> people) { 
    this.context = context; 
    this.people.addAll(people); 
    this.animating = new HashMap<>(); 
    this.animators = new HashMap<>(); 
} 

@Override 
public int getCount() { 
    return people.size(); 
} 

@Override 
public Person getItem(int position) { 
    return people.get(position); 
} 

@Override 
public long getItemId(int position) { 
    return position; 
} 

@Override 
public View getView(final int position, View convertView, ViewGroup parent) { 
    ViewHolder ViewHolder; 
    final Person p = people.get(position); 

    if (convertView == null) { 
     convertView = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)) 
      .inflate(R.layout.fragment_people_grid_peoples_item, null); 
     ViewHolder = new ViewHolder(); 
     ViewHolder.peopleGridItem = (PeopleGridItem) convertView.findViewById(R.id.fragment_people_grid_peoples_item_item); 
     convertView.setTag(ViewHolder); 
    } else { 
     ViewHolder = (ViewHolder) convertView.getTag(); 
    } 


    convertView.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      p.setSelected(!p.isSelected()); 
      notifyDataSetChanged(); 
     } 
    }); 

    if (animators.get(p.getId()) == null) 
     animators.put(p.getId(), ObjectAnimator.ofFloat(convertView, "rotation", 0, -2, 0, 2, 0)); 
    if (animating.get(p.getId()) == null) 
     animating.put(p.getId(), false); 

    if (p.isSelected()) { 
     if (!animating.get(p.getId())) { 
      animating.put(p.getId(), true); 
      animators.get(p.getId()).setTarget(convertView); 
      animators.get(p.getId()).setRepeatCount(ObjectAnimator.INFINITE); 
      animators.get(p.getId()).setDuration(300); 
      animators.get(p.getId()).start(); 
     } 
    } else { 
     animators.get(p.getId()).setTarget(convertView); 
     animating.put(p.getId(), false); 
     animators.get(p.getId()).end(); 
     animators.get(p.getId()).cancel(); 
    } 

    return convertView; 
} 
} 

有什麼錯嗎?

+0

我編輯了我的答案。我意識到,一開始我所說的,雖然是問題的根源,但並不是全部。 – 2015-04-09 14:28:01

回答

2

其他視圖抖動的原因是Android實現GridView的方式。爲了保留內存,它會回收視圖,以便只有顯示在屏幕上(或即將顯示)的內容纔會保存在內存中。任何回收的視圖都會被放入未使用的視圖池中,以供未來重用。這是參數「convertView」獲取其視圖的位置。

這意味着您的工作是在屏幕外保持對象的狀態。

if (convertView == null) { 
    convertView = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)) 
     .inflate(R.layout.fragment_people_grid_peoples_item, null); 
    ViewHolder = new ViewHolder(); 
    ViewHolder.peopleGridItem = (PeopleGridItem) convertView.findViewById(R.id.fragment_people_grid_peoples_item_item); 
    convertView.setTag(ViewHolder); 
} else { 
    ViewHolder = (ViewHolder) convertView.getTag(); 
} 

輸入else語句 - 其中convertView!= null - 表示您收到了回收視圖,而不是膨脹新的視圖。在這裏,你應該防止再循環的觀點繼續動搖。我認爲你實際上已經考慮到我之前提到過的(但是沒有成功),但是我會離開它來幫助其他人。就你而言,我認爲問題在於你無法停止你的ObjectAnimator。

if (animators.get(p.getId()) == null) 
    animators.put(p.getId(), ObjectAnimator.ofFloat(convertView, "rotation", 0, -2, 0, 2, 0)); 

這裏,如果當前Person的動畫師爲空。你創建一個新的。假設您點擊了person1。 ObjectAnimator1開始動畫person1。你向下滾動,這個視圖被重複用於person13。 ObjectAnimator13被創建,然後被告知結束並取消。無論ObjectAnimator13說什麼,ObjectAnimator1仍然可以動態重用視圖。

要解決這個問題,您可能需要在ViewHolder中存儲Person的當前id,以便您可以做的第一件事是結束之前的任何現有動畫。可能更好的方法是將ObjectAnimator存儲在ViewHolder中,然後不需要在HashMap中進行搜索。

+0

嘿邁克爾,謝謝你的回答,看起來不錯。我今天會嘗試。 – Rafael 2015-04-09 15:18:36

+0

好吧,讓我知道它是否適合你。祝你好運! – 2015-04-09 15:20:01

+0

它的工作原理!再次感謝你,你的回答非常有用。問題在於,當你和@Ashton Engberg說'BaseAdapter'在每個'getView'上回收'convertView'。 – Rafael 2015-04-09 21:26:33

1

您可以使用標籤比使用hashmaps更容易做到這一點......在每個getView調用中,驗證該人是否被選中 - 如果沒有,則取消動畫。並且因爲convertviews被回收,您必須重置狀態 getView調用(在需要的地方啓動動畫,取消不要的地方)。

public void getView(final int position, View convertView, ViewGroup parent) { 

    // inflate convertviews if necessary 

    Person person = people.get(position); 

    ObjectAnimator anim = (ObjectAnimator) convertView.getTag(R.id.tag_row_animation); 
    if (person.isSelected()) { 
    if (anim == null) { 
     anim = getAnimator(convertView); 
     anim.setTarget(convertView); 
     anim.start(); 
     convertView.setTag(R.id.tag_row_animation, anim); 
    } 
    } else { 
    if (anim != null) anim.cancel(); 
    convertView.setTag(R.id.tag_row_animation, null); 
    } 

    convertView.setTag(R.id.tag_list_person, person); 
    convertView.setOnClickListener(new View.OnClickListener() { 
    @Override public void onClick(View v) { 
     Person person = (Person) v.getTag(R.id.tag_list_person); 
     person.toggleSelected(); 
     notifyDataSetChanged(); 
    } 
    }); 

    return convertView; 
} 

public ObjectAnimator getAnimator(View v) { 
    ObjectAnimator a = ObjectAnimator.ofFloat(v, "rotation", 0, -2, 0, 2, 0); 
    a.setDuration(300); 
    a.setRepeatCount(ObjectAnimator.INFINITE); 
    return a; 
} 

至於爲什麼你的解決沒有工作的理由:因爲你的HashMap被保存到convertview參考,並convertview循環每n個位置(N =屏幕上的位置的數量,給予或採取1或2),他們將爲每個位置搖動%n == 0,因爲您設置爲搖動的上一個convertview現在將爲位於n位以外的網格單元搖動,因爲convertview已被回收。

+1

驗證此驗證碼:對於測試結賬的完整活動:http://pastebin.com/GmA1XHG1 – 2015-04-09 19:13:25