1

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

类级变量:

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

创建:

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;
        }
    } 
4

2 回答 2

3

让你的条件脱离getView()方法,这不是适合他们的地方。

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

您还说过,您需要它在里面,getView()因为您希望您的“选定”行改变它的背景。这不是真的。您知道要滚动到的位置,对吗?View所以你可以从你那里得到这个特定的,ListView并根据需要进行更改。

使用getChildAt()方法到达View特定位置。请记住,这getChildAt(0)将返回第一个可见元素,而不是整个列表中的第一个。这是此问题的解决方案:ListView getChildAt return 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();
于 2013-09-21T09:56:31.103 回答
1

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

于 2013-09-21T10:01:34.670 回答