Android:如何使用扩展布局类作为ListView行?

时间:2014-08-06 14:02:47

标签: java android listview

我正在创建一个简单的国际象棋时钟型计时器应用程序。我试图在ListView中显示玩家和他们留下的时间。我正在使用为这些行扩展RelativeLayout的自定义视图,以便我可以为其提供依次突出显示播放器的方法。

行布局类:

public class GameTimerView extends RelativeLayout {

    private TextView nameView;
    private TextView timerView;
    public GameTimerView(Context context) {
        super(context);

        LayoutInflater inflater = LayoutInflater.from(context);
        inflater.inflate(R.layout.timer_view, this);

        loadViews();
    }

    ...

    private void loadViews() {
        nameView = (TextView)findViewById(R.id.nameView);
        timerView = (TextView)findViewById(R.id.timerView);
    }

    public void setName(String name) {
        nameView.setText(name);
    }

    public void setTime(long timeInMillis) {
        timerView.setText(String.format("%02d:%02d",
                TimeUnit.MILLISECONDS.toMinutes(timeInMillis),
                TimeUnit.MILLISECONDS.toSeconds(timeInMillis) -
                        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeInMillis))
        ));
    }

    public void setActive() {
        this.nameView.setTextColor(Color.GREEN);
    }

    public void setInactive() {
        nameView.setTextColor(Color.BLACK);
    }
}

行布局XML(timer_view.xml):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/nameView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/timerView"
        android:text="@string/player_default_name" />

    <TextView
        android:id="@+id/timerView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="@string/zero_time" />

</RelativeLayout>

适配器:

public class playerArrayAdapter extends ArrayAdapter<Player> {
    private final Context context;
    private final ArrayList<Player> players;

    public playerArrayAdapter(Context context, ArrayList<Player> values) {
        super(context, R.layout.timer_view, values);
        this.context = context;
        this.players = values;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        GameTimerView playerView = new GameTimerView(context);
        players.get(position).setTimerView(playerView);

        return playerView;
    }
}

播放器类setTimerView函数:

public void setTimerView(GameTimerView timer) {
    this.timerView = timer;
    this.timerView.setName(this.name);
    this.timerView.setTime(this.totalCountDown);
    this.timerView.setInactive();
}

在活动的onCreate方法中

playerArrayAdapter playersAdapter = new playerArrayAdapter(
        getApplicationContext(),
        game.getPlayers()
);

ListView playersView = (ListView) findViewById(R.id.playerList);
playersView.setAdapter(playersAdapter);

首先,这似乎有效,并且所需的玩家名称和时间正确地呈现在列表中。但是,如果我稍后以编程方式调用示例Player.timerView.setActive(),则不会发生任何事情。

看过ListViews的几十个自定义适配器的例子后,似乎没有人这样使用它 - 视图总是直接在Apdater.getView()中膨胀。我想要扩展视图类的灵活性,但显然我做错了。

那么,为ListView行使用自定义视图类的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

首先,在对GameTimerView进行充气时,您在另一个内部有RelativeLayout

其次,要回答这个问题:最好不要在每次调用ArrayAdapter.getView()时重新创建视图,而是通过添加如下缓存来修改playerArrayAdapter

private List<View> views;

public playerArrayAdapter(Context context, ArrayList<Player> values) {
    super(context, R.layout.timer_view, values);
    views = new ArrayList<View>(values.length);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View playerView;
    if (position < views.size()) {
        playerView = views.get(position);
        if (playerView != null)
            return playerView;
    } else {
        while (views.size() < position)
            views.add(null);
    }
    playerView = new GameTimerView(context);
    views.add(position, playerView);
    players.get(position).setTimerView(playerView);
    return playerView;
}

如果这成功纠正了您的问题,则意味着之前,当将播放器设置为活动时,ListView会再次获取所有视图以进行渲染,重新创建它们,并删除之前的任何状态。

答案 1 :(得分:1)

根据getView()的{​​{1}}方法,它会创建一个可能导致您发出问题的新视图。

如果您确实要实施Adapter,请参阅自定义视图here的这个良好实现。希望这会帮助你开始。