Listview的行为不符合预期

时间:2013-09-21 09:41:32

标签: android android-listview

我有一个活动,我在后台播放媒体,我有一个列表视图,其中我有特定于歌词的行,整个歌词是一个数组。现在我希望当媒体播放器到达特定时间时,相关歌词(行)将滚动到列表视图的中心,并且该行以不同的阴影突出显示。为此,我在getview方法中使用smoothScrollto()函数。然而,一旦if else条件执行我的列表以不稳定的方式向上和向下滚动并且它的重复性太多以至于它是不可读的。以下是我的代码:

班级变量:

String [] LyricsE; 
String [] LyricsH; 
ListView listView;
private ArrayAdapter dataAdapter;

的onCreate:

dataAdapter = new arrayAdapter(MainActivity.this, LyricsH);

listView.setAdapter(dataAdapter);

自定义类:

public class arrayAdapter extends ArrayAdapter<String[]> {
        private final Context context;
        private final String[] lyrics;
        public arrayAdapter(Context context, String[]lyrics ) {
            super(context, R.layout.list);
            this.context = context;
            this.lyrics = lyrics; 

        }
        public int getCount() {
            return lyrics.length;

        }

        public String[] getItem(int position) {

            return (lyrics);
        }


        public long getItemId(int arg0) {

            return arg0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);



            if (convertView == null) { 
                convertView = inflater.inflate(R.layout.list, parent, false); 
            }
            TextView textView = ((TextView) convertView.findViewById(R.id.textView2));
            textView.setText(lyrics[position]);



            if(mediaPlayer.getCurrentPosition()/1000 > 0 && mediaPlayer.getCurrentPosition()/1000 < 20){
                listView.smoothScrollToPosition(3);
                System.out.println("FIrst if");
            }else if(mediaPlayer.getCurrentPosition()/1000 > 20 && mediaPlayer.getCurrentPosition()/1000 < 54){
                listView.smoothScrollToPosition(4);
                System.out.println("2 if");
            }else if(mediaPlayer.getCurrentPosition()/1000 > 54 && mediaPlayer.getCurrentPosition()/1000 < 67){
                listView.smoothScrollToPosition(5);
                System.out.println("3 if");
            }else if(mediaPlayer.getCurrentPosition()/1000 > 67 && mediaPlayer.getCurrentPosition()/1000 < 75){
                listView.smoothScrollToPosition(6);
                System.out.println("4 if");
            }else if(mediaPlayer.getCurrentPosition()/1000 > 20 && mediaPlayer.getCurrentPosition()/1000 < 54){
                listView.smoothScrollToPosition(7);
                System.out.println("5 if");
            }

            return convertView;
        }
    } 

2 个答案:

答案 0 :(得分:3)

getView()方法中获取您的条件,这对他们来说不是正确的地方。

您已经提到过您有一个处理程序,可以经常轮询媒体播放器的当前状态。使用它 - 这是正确的方法。

你还说,你需要它在getView()内,因为你希望你的'选定'行改变它的背景。这不是真的。你知道要滚动的位置,对吧?因此,您可以从View获取此特定ListView并根据需要进行更改。

使用getChildAt()方法将View置于特定位置。请记住,getChildAt(0)将返回FIRST VISIBLE元素,而不是整个列表中的第一个元素。以下是此问题的解决方案:ListView getChildAt returning null for visible children

编辑:

根据你提到的第二个问题 - 当你改变一个元素的颜色时,另一个也改变它的颜色。这种行为的原因是ListView为了有效地工作,创建元素尝试重用其他元素。大多数情况下它工作正常,因为我们通常希望所有元素都具有相同的样式 - 这样,它不必单独创建每个元素,而是使用现有元素。它发生在getView()中的Adapter方法中,它来自convertView

无论如何,这意味着您更愿意在getView()之后更改元素的样式。这也意味着您需要再次使用自定义适配器。 :)

我为你写了一个简单的适配器:

public class LyricsAdapter extends BaseAdapter {

    private final static int NOT_SELECTED_ID = 0;
    private final static int SELECTED_ID = 1;

    private LayoutInflater mInflater;
    private int mSelectedItem;
    private int selectedItemLayoutId, unselectedItemLayoutId;

    private String [] mList;

    public LyricsAdapter(Context context, String [] lyrics) {
        mInflater = LayoutInflater.from(context);
        this.mList = lyrics;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        boolean selected = (((LyricsAdapter)((ListView)parent).getAdapter()).getSelectedItem() == position);

        if (convertView == null) {
            if(selected) {
                convertView = mInflater.inflate(R.layout.selected_item_layout, parent, false);
                convertView.setId(SELECTED_ID);
            } else {
                convertView = mInflater.inflate(R.layout.unselected_item_layout, parent, false);
                convertView.setId(NOT_SELECTED_ID);
            }
        } else {
            if(selected && (convertView.getId() == NOT_SELECTED_ID)) {      // If it's selected, but still uses not-selected layout
                convertView = mInflater.inflate(R.layout.selected_item_layout, parent, false);
                convertView.setId(SELECTED_ID);
            } else if(!selected && (convertView.getId() == SELECTED_ID)) {  // If it's not selected, but still uses selected layout
                convertView = mInflater.inflate(R.layout.unselected_item_layout, parent, false);
                convertView.setId(NOT_SELECTED_ID);
            }
        }

        return convertView;
    }

    public int getCount() {
        return mList.length;
    }

    public Object getItem(int position) {
        return mList[position];
    }

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

    public void setSelectedItem(int pos) {
        mSelectedItem = pos;
    }

    public int getSelectedItem() {
        return mSelectedItem;
    }
}

我没有测试过,所以它可能有一些问题。但我希望你能有所了解。现在基本上你想要做的是,在你的代码中,你打电话:

listView.smoothScrollToPosition(position);

您还必须致电:

// Inform adapter which item is selected
((LyricsAdapter)listView.getAdapter()).setSelectedItem(position); 

// Refresh ListView's element so that selected one will update it's layout (or in other words - call `getView()` for all items again) 
((LyricsAdapter)listView.getAdapter()).notifyDataSetChanged(); 
listView.refreshDrawableState();
listView.invalidate();

答案 1 :(得分:1)

listView.smoothScrollToPosition()等不是ListAdapter的工作来决定。所有这些代码都应该放在包含ListView实例引用的类中,这可能是Activity / Fragment类。