如何实现一个两层的DrawerLayout

3
我正在尝试实现一个两级DrawerLayout。作为基线,我使用Google行星示例http://developer.android.com/training/implementing-navigation/nav-drawer.html。因此,我想扩展这个示例,以便从行星列表中选择一个行星,将该行星列表替换为该行星上城市的列表(除了地球,大部分为空 - 我仍在完善我的数据 :-))。
我想到了三种方法:
1. 替换ListView 2. 保留ListView,但替换其ArrayAdapter 3. 保留ListView和ArrayAdapter,但替换适配器的数据
因此,在我的DrawerItemClickListener中尝试选项3(这是最佳方法吗?),我执行以下操作...
arrayAdapter.clear(); 
arrayAdapter.addAll(arrayListOfCities);
arrayAdapter.notifyDataSetChanged(); 
mDrawerList.invalidateViews();
mDrawerList.forceLayout();
mDrawerList.refreshDrawableState();

但它似乎不起作用,即行星列表没有被城市列表替换。
我的方法正确吗?如果是这样,我该如何刷新列表?
1个回答

5

替换ListView

实际上没有必要这样做。


保留ListView,但替换其ArrayAdapter

这是最容易实现的方法。首先,在res/values/strings.xml中添加以下字符串数组(城市名称):

<string-array name="mercury_array">
    <item>Undiscovered City 1 (Mercury)</item>
    <item>Undiscovered City 2 (Mercury)</item>
    <item>Undiscovered City 3 (Mercury)</item>
    <item>Undiscovered City 4 (Mercury)</item>
</string-array>
<string-array name="venus_array">
    <item>Undiscovered City 1 (Venus)</item>
    <item>Undiscovered City 2 (Venus)</item>
    <item>Undiscovered City 3 (Venus)</item>
    <item>Undiscovered City 4 (Venus)</item>
</string-array>
<string-array name="earth_array">
    <item>New York</item>
    <item>Hong Kong</item>
    <item>New Delhi</item>
    <item>London</item>
</string-array>
<string-array name="mars_array">
    <item>Undiscovered City 1 (Mars)</item>
    <item>Undiscovered City 2 (Mars)</item>
    <item>Undiscovered City 3 (Mars)</item>
    <item>Undiscovered City 4 (Mars)</item>
</string-array>
<string-array name="jupiter_array">
    <item>Undiscovered City 1 (Jupiter)</item>
    <item>Undiscovered City 2 (Jupiter)</item>
    <item>Undiscovered City 3 (Jupiter)</item>
    <item>Undiscovered City 4 (Jupiter)</item>
</string-array>
<string-array name="saturn_array">
    <item>Undiscovered City 1 (Saturn)</item>
    <item>Undiscovered City 2 (Saturn)</item>
    <item>Undiscovered City 3 (Saturn)</item>
    <item>Undiscovered City 4 (Saturn)</item>
</string-array>
<string-array name="uranus_array">
    <item>Undiscovered City 1 (Uranus)</item>
    <item>Undiscovered City 2 (Uranus)</item>
    <item>Undiscovered City 3 (Uranus)</item>
    <item>Undiscovered City 4 (Uranus)</item>
</string-array>
<string-array name="neptune_array">
    <item>Undiscovered City 1 (Neptune)</item>
    <item>Undiscovered City 2 (Neptune)</item>
    <item>Undiscovered City 3 (Neptune)</item>
    <item>Undiscovered City 4 (Neptune)</item>
</string-array>

MainActivity中创建一个名为loadContentList(int)的方法。这个方法将在主列表项点击时被调用:
private void loadContentList(int position) {

    setTitle(mPlanetTitles[position]);

    String[] content;

    switch(position) {
    case 0:
            content = getResources().getStringArray(R.array.mercury_array);
            break;
    case 1:
            content = getResources().getStringArray(R.array.venus_array);
            break;
    case 2:
            content = getResources().getStringArray(R.array.earth_array);
            break;
    case 3:
            content = getResources().getStringArray(R.array.mars_array);
            break;
    case 4:
            content = getResources().getStringArray(R.array.jupiter_array);
            break;
    case 5:
            content = getResources().getStringArray(R.array.saturn_array);
            break;
    case 6:
            content = getResources().getStringArray(R.array.uranus_array);
            break;
    case 7:
            content = getResources().getStringArray(R.array.neptune_array);
            break;
    default:
            content = getResources().getStringArray(R.array.neptune_array);     
}

    // Change ListView's adapter    
    mDrawerList.setAdapter(new ArrayAdapter<String>(this,
            R.layout.drawer_list_item, content));

    // Change OnItemClickListener // CityItemClickListener is defined below
    mDrawerList.setOnItemClickListener(new CityItemClickListener());
}

由于我们希望在单击星球项目时更新ListView,因此我们将更改DrawerItemClickListener的方法体并调用新添加的loadContentList(int)

/* The click listner for ListView in the navigation drawer */
private class DrawerItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        //selectItem(position);
        loadContentList(position);
    }
}

我们需要另一个OnItemClickListener来在单击城市时更改片段。
private class CityItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        // This is the method that was being called on planet click 
        // in the original example. Implementation of it is up to you
        selectItem(position);
    }
}

保留ListView和ArrayAdapter,但替换适配器的数据。
定义ArrayAdapter:
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;    
---------> private ArrayAdapter<String> mAdapter;     

在MainActivity的onCreate(Bundle)方法中:
ArrayList<String> planetList = new ArrayList<String>();

planetList.addAll(Arrays.asList(mPlanetTitles));

mAdapter = new ArrayAdapter<String>(this,
            R.layout.drawer_list_item, planetList);

// set up the drawer's list view with items
mDrawerList.setAdapter(mAdapter);      

我们需要传递一个ArrayList,这样在调用mAdapter.clear()时就可以避免UnsupportedOperationException异常。

loadContentList(int)修改为以下内容:

private void loadContentList2(int position) {

    setTitle(mPlanetTitles[position]);

    String[] content;

    switch(position) {

        ....
        ....
    }

    ArrayList<String> cityList = new ArrayList<String>();

    cityList.addAll(Arrays.asList(content));

    mAdapter.clear();

    mAdapter.addAll(cityList);

    // update
    mAdapter.notifyDataSetChanged();        

    // Change on item click listener
    mDrawerList.setOnItemClickListener(new CityItemClickListener());

}

CityItemClickListener和DrawerItemClickListener将保持与以前相同。唯一的变化是:我们不会在点击星球列表项时创建新的ArrayAdapter。

您需要想出一种方式(例如按钮),让用户从城市视图返回星球列表。

我还建议您研究ExpandableListView。它可能更优雅地解决您的问题。


非常感谢。结果证明我的代码实际上是有效的,我只是错误地添加了错误的字符串数组。傻瓜!!感谢您指向ExpandableListView。我最初忽略了使用ExpandableListView,因为有些情况下我想直接调用城市列表,即不通过行星列表导航。然而,正如您所指出的,我的方法会创建从城市到行星的导航问题,在ExpandableListView中得到解决。因此,我最终使用了ExpandableListView,然后在适当的情况下使用单独的ListView来显示城市。再次感谢。 - pinoyyid
@pinoyyid 实际上,从城市导航回到星球并不是什么大问题。您可以添加一个按钮,该按钮仅在显示城市列表时可见。单击后,重置适配器以保持“mPlanetTitles”并刷新ListView。但是,ExpandableListView 更适合您的应用程序需求。如果城市数量相当大,甚至可以使用 GridView(具有 2 列)来显示城市,并使用 ListView 来显示星球。 - Vikram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接