相信很多人都用过Adapter,但是Adapter嵌套Adapter确很少使用,主要是这样的需求也不多,最近要做一个说明书类的应用,左边实现目录的嵌套,点击一级目录弹出二级目录,一级目录为一个Adapter,二级目录又是一个Adapter。当我们点击左面的条目时右边又要动态的显示文本或者图片内容,这里我用了两个Fragment。一个用来装目录列表,一个用来显示内容。
大致界面:
点击左边目录弹出右边内容,点击一级目录开启或关闭子目录
MainActivity.java
package com.tcl.userguide;
import com.tcl.userguide.R;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.webkit.WebView;
/**
* 用户指南主界面
*/
public class MainActivity extends Activity {
private FragmentManager manager;
private FragmentTransaction transaction;
/**
* 左侧目录导航栏
*/
private LeftFragment leftFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
initView();
}
/**
* 初始化view
*/
private void initView(){
manager = getFragmentManager();
transaction = manager.beginTransaction();
leftFragment = new LeftFragment(this);
transaction.add(R.id.ll_left_frag, leftFragment, "leftFragment");
transaction.commit();
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<LinearLayout
android:id="@+id/ll_left_frag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:background="@color/background_left"
android:orientation="vertical" >
</LinearLayout>
<LinearLayout
android:id="@+id/ll_right_frag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="7"
android:background="@color/white"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
大部分代码都很简单,直接能看懂的就不解释了,直接贴代码
package com.tcl.userguide;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.tcl.userguide.R;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
/**
* 左侧目录栏
*/
public class LeftFragment extends Fragment{
private static String TAG="LeftFragment";
private Context mContext;
/**
* 左侧目录listView
*/
private ListView listView;
/**
* 左侧目录适配器
*/
private LeftTabAdapter adapter;
/**
* 目录数据组
*/
private Map<String,ArrayList<String>> data;
/**
* 目录数据组
*/
private List<String> list;
/**
* 读取xml配置文件,获取目录信息
*/
private XmlReader readXml = null;
private FragmentManager manager;
private FragmentTransaction transaction;
public LeftFragment(Context context){
this.mContext = context;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.left_fragment, null);
initView(view);
return view;
}
/**
* 初始化View
* @param view
*/
private void initView(View view){
listView = (ListView) view.findViewById(R.id.lv_tab_listview);
getData();
adapter = new LeftTabAdapter(mContext,data,list,this);
listView.setAdapter(adapter);
manager = getFragmentManager();
RightFragment fragment = new RightFragment(mContext);
transaction = manager.beginTransaction();
transaction.replace(R.id.ll_right_frag, fragment,"rightFragment");
Bundle bundle = new Bundle();
bundle.putString("item","1");
fragment.setArguments(bundle);
transaction.commit();
}
/**
* 初始化左侧目录数据
* @return data
*/
private void getData(){
InputStream inputStream = mContext.getClass().getClassLoader().getResourceAsStream("trees.xml");
readXml = new XmlReader(inputStream);
list = readXml.getParentList();
data = readXml.getFullData();
}
}
这里左侧目录内容通过读取一个trees.xml的文件,这样如果目录内容有变化直接修改xml文件就可以,代码不需要做改动
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<parent id="1" name="目录1"></parent>
<parent id="2" name="目录2"></parent>
<parent id="3" name="目录3"></parent>
<parent id="4" name="目录4"></parent>
<parent id="5" name="目录5"></parent>
<parent id="6" name="目录6">
<item id="6.1"> 6-子目录1</item>
<item id="6.2"> 6-子目录2</item>
<item id="6.3"> 6-子目录3</item>
</parent>
<parent id="7" name="目录7">
<item id="7.1"> 7-子目录1</item>
<item id="7.2"> 7-子目录2</item>
</parent>
</catalog>
读取xml文件代码
package com.tcl.userguide;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.util.Log;
import android.util.Xml;
/**
* 读取xml文件
*/
public class XmlReader {
private static String TAG="XmlReader";
/**
* 根据一级目录读取的二级目录数据组
*/
private Map<String, ArrayList<String>> data = null;
/**
* 一级目录
*/
private List<String> list = null;
public XmlReader(InputStream xml) {
try {
ReadXml(xml);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 读取xml文件
* @param xml
* @throws XmlPullParserException
*/
private void ReadXml(InputStream xml) throws Exception {
String parantIndex = null;
String parantName = null ;
ArrayList<String> items = null;
String itemIndex = null;
String itemName = null;
XmlPullParser pullParser = Xml.newPullParser();
pullParser.setInput(xml, "UTF-8");//为Pull解析器设置要解析的XML数据
int event = pullParser.getEventType();
while(event != XmlPullParser.END_DOCUMENT){
switch (event) {
case XmlPullParser.START_DOCUMENT:
list = new ArrayList<String>();
data = new HashMap<String, ArrayList<String>>();
break;
case XmlPullParser.START_TAG:
if("parent".equals(pullParser.getName())){
items = new ArrayList<String>();
parantIndex = pullParser.getAttributeValue(0);
parantName = pullParser.getAttributeValue(1);
}
if("item".equals(pullParser.getName())){
itemIndex = pullParser.getAttributeValue(0);
String text = pullParser.nextText();
itemName = itemIndex+" "+text;
items.add(itemName);
}
break;
case XmlPullParser.END_TAG:
if("parent".equals(pullParser.getName())){
list.add(parantIndex+"、"+parantName);
Log.i(TAG, "items.size()="+items.size());
if(items.size() > 0){
data.put(parantIndex+"、"+parantName, items);
}else{
data.put(parantIndex+"、"+parantName, null);
}
items = null;
}
break;
default:
break;
}
event = pullParser.next();
}
}
/**
* 获取一级目录列表
* @return
*/
public List<String> getParentList(){
return list;
}
/**
* 根据一级目录列表获取二级和三级列表,二级三级列表会一起显示
* @return
*/
public Map<String, ArrayList<String>> getFullData(){
return data;
}
}
left_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_left"
android:orientation="vertical" >
<ListView
android:id="@+id/lv_tab_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/black"
android:dividerHeight="1px"/>
</LinearLayout>
左侧一级目录适配器
package com.tcl.userguide;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.tcl.userguide.R;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
/**
* 左侧目录栏目适配器
*/
public class LeftTabAdapter extends BaseAdapter {
private Context mContext;
private FragmentManager manager;
private FragmentTransaction transaction;
private Fragment mFragment;
/**
* 目录数据组
*/
private Map<String, ArrayList<String>> mdata;
/**
* 目录数据组
*/
private List<String> mlist;
/**
* 缓存类对象
*/
private ViewCache viewCache;
private LayoutInflater inflater;
private static String TAG = "LeftTabAdapter";
/**
* 显示哪个二级目录
*/
public static int mParentItem = -1;
/**
* 是否显示二级目录
*/
public static boolean mbShowChild = false;
public LeftTabAdapter(Context context, Map<String, ArrayList<String>> data,
List<String> list,Fragment fragment) {
this.mContext = context;
this.mFragment= fragment;
this.mdata = data;
this.mlist = list;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mlist.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mlist.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
final int position_item = position;
if (convertView == null) {
inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.left_listview_item, null);
}
viewCache = getViewCache(convertView);
viewCache.tab.setText(mlist.get(position) + "");
manager = mFragment.getFragmentManager();
// 点击那个弹出那个,如果已经弹出就收回子listView
if (mParentItem == position && mbShowChild) {
// 子listView实在这里加载数据的
if (mdata.get(mlist.get(position)) != null
&& mdata.get(mlist.get(position)).size() > 0) {
LeftTabItemAdapter adapter = new LeftTabItemAdapter(mContext, mdata.get(mlist
.get(position)),mFragment);
viewCache.listView.setAdapter(adapter);
viewCache.listView.setVisibility(View.VISIBLE);
}
} else {
viewCache.listView.setVisibility(View.GONE);
}
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (mParentItem == position_item && mbShowChild) {
mbShowChild = false;
}else {
mbShowChild = true;
}
mParentItem = position_item;
notifyDataSetChanged();
RightFragment fragment = new RightFragment(mContext);
transaction = manager.beginTransaction();
transaction.replace(R.id.ll_right_frag, fragment,"rightFragment");
Bundle bundle = new Bundle();
int index = mlist.get(position).lastIndexOf("、");
String item = mlist.get(position).substring(0, index);
bundle.putString("item",item+"");
fragment.setArguments(bundle);
transaction.commit();
}
});
return convertView;
}
private ViewCache getViewCache(View convertView) {
ViewCache viewHolder = (ViewCache) convertView.getTag();
if (viewHolder == null) {
viewHolder = new ViewCache(convertView);
convertView.setTag(viewHolder);
}
return viewHolder;
}
/**
* 缓冲类
*
* @author LiuHanze
*/
private final class ViewCache {
public TextView tab;
public ChildListView listView;
public ViewCache(View view) {
tab = (TextView) view.findViewById(R.id.tv_tab_title);
listView = (ChildListView) view
.findViewById(R.id.lv_tab_item_listview);
}
}
}
left_listview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_left"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_tab_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10px"
android:paddingLeft="30px"
android:text="你好"
android:textColor="@color/white"
android:textSize="30px" />
<com.tcl.userguide.ChildListView
android:id="@+id/lv_tab_item_listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@color/black"
android:dividerHeight="1px"
android:layout_marginLeft="80px"/>
</LinearLayout>
在上面的二级目录之所以没有直接使用ListView是因为adapter嵌套adapter会出现子adapter显示不全问题,可以自己简单定义一个ChildListView集成ListView
package com.tcl.userguide;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
/**
* 子listView,重写是为了解决listView嵌套listView后,子listView显示不全问题
*/
public class ChildListView extends ListView {
public ChildListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public ChildListView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public ChildListView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
二级目录适配器
package com.tcl.userguide;
import java.util.List;
import com.tcl.userguide.R;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
/**
* 左侧目录条目点击后展示item适配器
*/
public class LeftTabItemAdapter extends BaseAdapter{
private static String TAG="LeftTabItemAdapter";
private Context mContext;
private Fragment mFragment;
/**
* 条目数据组
*/
private List<String> mlist;
private ViewCache viewCache;
private LayoutInflater inflater;
private FragmentManager manager;
private FragmentTransaction transaction;
public LeftTabItemAdapter(Context context,List<String> list,Fragment fragment){
this.mContext = context;
this.mFragment = fragment;
this.mlist = list;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mlist.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mlist.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
if(null == convertView){
inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.left_item_listview_item, null);
}
viewCache = getViewCache(convertView);
viewCache.item.setText(mlist.get(position)+"");
manager = mFragment.getFragmentManager();
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
RightFragment fragment = new RightFragment(mContext);
transaction = manager.beginTransaction();
transaction.replace(R.id.ll_right_frag, fragment,"rightFragment");
Bundle bundle = new Bundle();
int index = mlist.get(position).indexOf(" ");
String item = mlist.get(position).substring(0, index);
bundle.putString("item",item+"");
fragment.setArguments(bundle);
transaction.commit();
}
});
return convertView;
}
private ViewCache getViewCache(View convertView) {
ViewCache viewHolder = (ViewCache) convertView.getTag();
if (viewHolder == null) {
viewHolder = new ViewCache(convertView);
convertView.setTag(viewHolder);
}
return viewHolder;
}
/**
* 缓冲类
* @author LiuHanze
*/
private final class ViewCache{
public TextView item;
public ViewCache(View view){
item = (TextView) view.findViewById(R.id.tv_item);
}
}
}
left_item_listview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background_left"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_item"
android:layout_width="match_parent"
android:layout_height="60px"
android:gravity="center_vertical"
android:text="000"
android:textColor="@color/white"
android:textSize="26px"
/>
</LinearLayout>
最后是右边的Fragment,显示内容为本地网页内容,当然你也可以修改成任何想要的展示方式,或者是网络上的内容
package com.tcl.userguide;
import android.annotation.SuppressLint;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.webkit.WebViewClient;
/**
* 显示内容
*/
@SuppressLint("SetJavaScriptEnabled")
public class RightFragment extends Fragment{
private WebView webView;
private String item ;
private Context mContext;
private static String TAG = "RightFragment";
public RightFragment(Context context) {
// TODO Auto-generated constructor stub
this.mContext = context;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.right_fragment, null);
initView(view);
return view;
}
/**
* 初始化view
* @param view
*/
private void initView(View view){
Bundle bundle = getArguments();
if (bundle != null) {
item = bundle.getString("item");
}
webView = (WebView) view.findViewById(R.id.wv_webview);
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// TODO Auto-generated method stub
if(url.indexOf("tel:")<0){
view.loadUrl(url);
}
return true;
}
});
webView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
// TODO Auto-generated method stub
return true;
}
});
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("file:///android_asset/"+item+".html");
}
}
right_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical" >
<WebView
android:id="@+id/wv_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
剩下的就是几个网页了