使用实现了单选功能的ListView,不要问为什么不使用RecyclerView,RecyclerView真的做得不如ListView和GridView完善全面,但是RecyclerView真的是很灵活(目前发现RecyclerView有几个bug,以后再吐槽),RecyclerView也有自己的优势,这里解释一下我们为啥使用了ListView,ListView加上Fragment,点击ListView的item来切换Fragment,Fragment是可以保存状态的,使用了hide和show事务,可以根据下发的数据来创建对面的Fragment,就是创建对应的Fragment类型。下面先看看图片吧:
ListView可以支持对选和单选:
tabList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);//单选
tabList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);//多选
看代码之前先看一下工程结构:
java代码:
xml文件:
要实现单选那么ListView的item的布局ViewGroup需要实现Checkable接口,下面是item_tab_list.xml
<?xml version="1.0" encoding="utf-8"?>
<com.example.bottommenudemo.CheckableRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="80dp" android:gravity="center_vertical" android:orientation="horizontal">
<TextView android:id="@+id/tabName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:clickable="false" android:layout_centerVertical="true" android:maxLines="1" android:text="标题栏" android:layout_alignParentLeft="true" android:textColor="@android:color/white" android:textSize="15sp" />
<CheckedTextView android:layout_width="8dip" android:layout_height="80dp" android:background="@drawable/checkbox_selector" android:gravity="center" android:layout_alignParentRight="true" android:paddingLeft="8dp" />
</com.example.bottommenudemo.CheckableRelativeLayout>
需要把CheckedTextView这个选中flag以外的控件设置为android:clickable=”false”
下面是自定义的RelativeLayout,主要是实现了Checkable接口:
package com.example.bottommenudemo;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Checkable;
import android.widget.RelativeLayout;
/** * Created by Danxx on 2016/4/29. */
public class CheckableRelativeLayout extends RelativeLayout implements Checkable{
private static final int CHECKABLE_CHILD_INDEX = 1;
private Checkable child;
public CheckableRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
child = (Checkable) getChildAt(CHECKABLE_CHILD_INDEX);
}
@Override
public boolean isChecked() {
return child.isChecked();
}
@Override
public void setChecked(boolean checked) {
child.setChecked(checked);
}
@Override
public void toggle() {
child.toggle();
}
}
ListView的choiceMode可以在代码中设置,也可以在xml文件中设置:
tabList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);//单选(代码实现)
android:choiceMode="singleChoice" //单选(xml中实现)
其余的ListView使用跟一般的ListView使用是一样的,这个时候我单击ListView的item就可以实现单选功能了。
Fragment的创建我封装了一下下,FragmentFactory.java就是用来创建对应的Fragment,需要传入FragmentBean和与ListView对应的position:
package com.example.bottommenudemo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import java.util.HashMap;
/** * fragment build factory * Created by Danxx on 2016/4/28. */
public class FragmentFactory {
/**fragment缓存**/
private static HashMap<String,Fragment> fragments = new HashMap<String, Fragment>();
public static Fragment buildFragment(FragmentBean data ,int pos){
Fragment fragment = null;
String id = data.getID();
String name = data.getName();
int position = data.getPosition();
String url = data.getUrl();
fragment = fragments.get(String.valueOf(pos));
if(fragment != null){
return fragment;
}
if(id.equalsIgnoreCase(Common.BACKGROUND)){
fragment = new FragmentSetBackground();
}else if(id.equalsIgnoreCase(Common.RECOMMEND)){
fragment = new FragmentSetRecommend();
}else if(id.equalsIgnoreCase(Common.SCREENSAVER)){
fragment = new FragmentSetScreensaver();
}else if(id.equalsIgnoreCase(Common.ABOUT)){
fragment = new FragmentSetAbout();
}
Bundle bundle = new Bundle();
bundle.putString("id" ,id);
bundle.putString("name" ,name);
bundle.putInt("position", position);
bundle.putString("url" , url);
if(fragment != null){
//传递简单的参数
fragments.put(String.valueOf(pos), fragment);
fragment.setArguments(bundle);
}
return fragment;
}
}
直接看MainActivity的代码:
package com.example.bottommenudemo;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView tabList;
private List<FragmentBean> fragmentData = new ArrayList<FragmentBean>();
private MyAdapater mAdapter;
private int lastPosition = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_2_main);
Log.d("danxx", "onCreate--->");
tabList = (ListView) findViewById(R.id.tabList);
/************************填充假数据,可以根据服务器下发的数据来初始化数据(一定得给出模板类型layout_code)*************************/
FragmentBean backGround = new FragmentBean(Common.BACKGROUND,0,"背景0","http://www.dusa.com/da/index.jsp");
fragmentData.add(backGround);
FragmentBean recommend = new FragmentBean(Common.RECOMMEND,1,"推荐>1","http://www.dusa.com/food/list.jsp");
fragmentData.add(recommend);
FragmentBean screensaver = new FragmentBean(Common.SCREENSAVER,2,"背景>2" ,"http://www.meitu.com/pic/con.jsp");
fragmentData.add(screensaver);
FragmentBean about = new FragmentBean(Common.ABOUT,3,"关于>3","http://www.alibaba.com/good/index.php");
fragmentData.add(about);
FragmentBean backGround2 = new FragmentBean(Common.BACKGROUND,4,"背景>4","http://www.dusa.com/da/index.jsp");
fragmentData.add(backGround2);
FragmentBean about2 = new FragmentBean(Common.ABOUT,5,"关于>5","http://www.alibaba.com/good/index.php");
fragmentData.add(about2);
FragmentBean recommend2 = new FragmentBean(Common.RECOMMEND,6,"推荐>6","http://www.dusa.com/food/list.jsp");
fragmentData.add(recommend2);
FragmentBean screensaver2 = new FragmentBean(Common.SCREENSAVER,7,"背景>7" ,"http://www.meitu.com/pic/con.jsp");
fragmentData.add(screensaver2);
FragmentBean about3 = new FragmentBean(Common.ABOUT,8,"关于>8","http://www.alibaba.com/good/index.php");
fragmentData.add(about3);
mAdapter = new MyAdapater(this , fragmentData);
tabList.setAdapter(mAdapter);
tabList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
mAdapter.notifyDataSetChanged();
/**根据用户点击来切换fragment**/
tabList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.d("danxx" ,"position-->"+position);
if(lastPosition == position){
return;
}
if(lastPosition != -1){
Fragment fromFragment = getSupportFragmentManager().findFragmentByTag(String.valueOf(lastPosition));
if(fromFragment==null){
fromFragment = buildFragment(lastPosition);
}
Fragment toFragment = getSupportFragmentManager().findFragmentByTag(String.valueOf(position));
if(toFragment == null){
toFragment = buildFragment(position);
}
switchContent(fromFragment ,lastPosition ,toFragment ,position);
}else{
/*第一次显示fragment*/
getSupportFragmentManager().beginTransaction().
add(R.id.content ,FragmentFactory.buildFragment(mAdapter.getItemData(position) ,position) ,String.valueOf(position)).commit();
}
lastPosition = position;
}
});
}
public Fragment buildFragment(int position){
/**根据模板类型layout_code的不同来创建对应的fragment**/
return FragmentFactory.buildFragment(mAdapter.getItemData(position) ,position);
}
/** * 切换显示的fragment * @param fromFragment * @param fromPos * @param toFragment * @param toPos */
public void switchContent(Fragment fromFragment ,int fromPos, Fragment toFragment ,int toPos) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!toFragment.isAdded()) { // 先判断是否被add过
transaction.hide(fromFragment).add(R.id.content, toFragment ,String.valueOf(toPos)).commit(); // 隐藏当前的fragment,add下一个到Activity中
} else {
transaction.hide(fromFragment).show(toFragment).commit(); // 隐藏当前的fragment,显示下一个
}
}
class MyAdapater extends BaseAdapter{
private List<FragmentBean> mData;
private Context mContext;
public MyAdapater(Context context , List<FragmentBean> data){
this.mContext = context;
this.mData = data;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(position);
}
public FragmentBean getItemData(int position){
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
/** * 数据不会很多,所以没有使用ViewHolder复用 * @param position * @param convertView * @param parent * @return */
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
Log.d("danxx" ,"getView_position-->"+position);
final View view = LayoutInflater.from(mContext).inflate(R.layout.item_tab_list , null);
TextView tabName = (TextView) view.findViewById(R.id.tabName);
tabName.setText(mData.get(position).getName());
return view;
}
}
}
MainActivity.java需要留意的就是,我们在切换Fragment的时候并没有把所有的Fragment都找到,然后hide掉,我觉得这样真的很没有必要,耗时耗力,还显得很蠢,我使用了switchContent方法来做这个操作,从一个Fragment切换到另一个Fragment,就直接是hide现在看到的Fragment,show我们需要的Fragment,这样我们切换Fragment就总是对两个Fragment做处理,是不是简洁了很多?
/** * 切换显示的fragment * @param fromFragment * @param fromPos * @param toFragment * @param toPos */
public void switchContent(Fragment fromFragment ,int fromPos, Fragment toFragment ,int toPos) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!toFragment.isAdded()) { // 先判断是否被add过
transaction.hide(fromFragment).add(R.id.content, toFragment ,String.valueOf(toPos)).commit(); // 隐藏当前的fragment,add下一个到Activity中
} else {
transaction.hide(fromFragment).show(toFragment).commit(); // 隐藏当前的fragment,显示下一个
}
}