Android 如何更改 ListView 中不可见项目的背景颜色

How to change the background color of a non-visible item in ListView in Android

我正在尝试制作一个导航抽屉,它根据从应用程序的另一部分接收到的整数更改 ListView 中项目的背景颜色——即不基于单击的项目。我已经设法为导航抽屉中的两个单独的项目着色,但显然我的方法只适用于可见的项目。我尝试做一个解决方法,涉及在更改背景颜色之前滚动到所需的项目,但我无法想出一种方法来计算向下滚动后项目的数量,因为 getChildAt(position) 似乎开始在第一个可见项目处。

有什么办法可以解决这个问题而不必重新做整个导航抽屉吗?我搜索了一些关于如何制作这样的侧边栏菜单的指南,但大多数意味着我必须在 XML 中设置静态项目 – 因为我的列表需要定期更改,所以我认为这是最简单的方法, 但据我所知,这也可能是一个糟糕的方法。

这是 运行 onCreate 中的代码:

mTitle = mDrawerTitle = getTitle();
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
        R.drawable.ic_drawer, R.string.navigation_drawer_open,
        R.string.navigation_drawer_close) {

    public void onDrawerClosed(View view) {
        super.onDrawerClosed(view);
        getActionBar().setTitle(mTitle);
    }

    public void onDrawerOpened(View drawerView) {
        super.onDrawerOpened(drawerView);
        getActionBar().setTitle(mDrawerTitle);
        dList = (ListView) findViewById(R.id.left_drawer);

        // My work-around to not get force close if item isn't visible
        if (itemOne > -1) {
            int visibleChildCount = (dList.getLastVisiblePosition() - dList
                    .getFirstVisiblePosition()) + 1;
            if (visibleChildCount > itemOne)
                dList.getChildAt(itemOne).setBackgroundColor(
                        Color.parseColor("#d3d3d3"));
        }
        if (itemTwo > -1) {
            int visibleChildCount = (dList.getLastVisiblePosition() - dList
                    .getFirstVisiblePosition()) + 1;
            if (visibleChildCount > itemTwo)
                dList.getChildAt(itemTwo).setBackgroundColor(
                        Color.parseColor("#33B5E5"));
        }

    }
};


    mDrawerLayout.setDrawerListener(mDrawerToggle);
    getActionBar().setDisplayHomeAsUpEnabled(true);
    getActionBar().setHomeButtonEnabled(true);

其余代码:

dLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
dList = (ListView) findViewById(R.id.left_drawer);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myArrayOfItems);
dList.setAdapter(adapter);

dList.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
        dList.setItemChecked(position, true);
        dLayout.closeDrawers();
        stateChanged = true;

            // Non-relevant action when item is clicked

    }
});

最后,activity XML:

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

<RelativeLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerHorizontal="true"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

     <!-- Items in my main activity -->

</RelativeLayout>

<ListView android:id="@+id/left_drawer"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:choiceMode="singleChoice"
    android:divider="@android:color/transparent"
    android:dividerHeight="0dp"
    android:background="#fff"/>

</android.support.v4.widget.DrawerLayout>

如果您需要任何其他信息,请告诉我。如果我错过了其他任何问题的答案或者这是一个愚蠢的问题,我很抱歉。我已经尝试搜索了一段时间,但由于我是初学者,我还没有完全弄清楚如何做到这一点,所以如果有人能帮助我,我将不胜感激!

编辑:

多亏了 darnmason,我终于让它工作了。如果有人感兴趣,上面的代码将适用于以下更改。

将行 adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, myArrayOfItems); 更改为:

adapter = new NavigationAdapter(this, android.R.layout.simple_list_item_1, myArrayOfItems);

然后使用以下内容创建 class NavigationAdapter.java(并确保整数 itemOne/itemTwo 可以通过某种方式从主 activity 访问):

import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;

public class NavigationAdapter extends ArrayAdapter<String> {

    // Create constructor matching super
    public NavigationAdapter(Context context, int resource, String[] objects) {
        super(context, resource, objects);
    }

    // Override method so that you can modify the view
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = super.getView(position, convertView, parent);
        // modify your view depending on position
        if (position == itemOne) {
                boolean positionOne = true;
            view.setBackgroundColor(positionOne ? Color.parseColor("#d3d3d3") : Color.WHITE);
        } else if (position == itemTwo) {
                boolean positionTwo = true;
            view.setBackgroundColor(positionTwo ? Color.parseColor("#33B5E5") : Color.WHITE);
        } else
            view.setBackgroundColor(Color.WHITE);

        return view;
    }
}

此外,请确保从我之前的代码中删除以下几行:

        // My work-around to not get force close if item isn't visible
        if (itemOne > -1) {
            int visibleChildCount = (dList.getLastVisiblePosition() - dList
                    .getFirstVisiblePosition()) + 1;
            if (visibleChildCount > itemOne)
                dList.getChildAt(itemOne).setBackgroundColor(
                        Color.parseColor("#d3d3d3"));
        }
        if (itemTwo > -1) {
            int visibleChildCount = (dList.getLastVisiblePosition() - dList
                    .getFirstVisiblePosition()) + 1;
            if (visibleChildCount > itemTwo)
                dList.getChildAt(itemTwo).setBackgroundColor(
                        Color.parseColor("#33B5E5"));
        }

列表中每个项目的渲染应该在适配器中处理。你真正应该做的是扩展 ArrayAdapter 并覆盖 getView 成为这样的东西:

View view = super.getView(position, convertView, parent);
boolean selected = position matches any of your indexes;
view.setBackgroundColor(selected ? selectedColor : normalColor);
return view;

另一种设置背景的方法是使用具有选定状态和默认状态的可绘制状态列表。然后你只需要调用 view.setSelected(selected)

编辑:扩展 ArrayAdapter

创建一个新文件,我喜欢创建一个新包来将所有自定义适配器分组到 com.domain.name.adapters 之类的东西下。

// Create new class extending ArrayAdapter<String>
public class NavigationAdapter extends ArrayAdapter<String> {

    // Create constructor matching super
    public NavigationAdapter(Context context, int resource, String[] objects) {
        super(context, resource, objects);
    }

    // Override method so that you can modify the view
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = super.getView(position, convertView, parent);
        // modify your view depending on position
        return view;
    }
}

然后只需将代码中的 NavigationAdapter 替换为 ArrayAdapter。您可能必须公开在 NavigationAdapter 上设置选定索引的方法,除非您将它们放在某个全球可访问的位置。