先来看看微信整体布局方式及市面上一些常见的应用大致布局方式,几乎都是采用顶部或者底部一个菜单栏控制方式,然后中间一些内容显示界面,下面是微信应用、腾讯新闻和163网易邮箱应用的部分界面效果图,如下:
今天将对这种常见布局方式结合个人所做过的项目进行一个汇总,在最早出来工作之时,那时多数的人做这种应用是采用tabhost去实现的,tabhost可以根据项目需求选择性加载多张tab页,每一张的tab显示页都是一个activity,不过这种方式现在看来已经过时被淘汰了,现在的应用多数是采用activity碎片化方式去实现,即使用fragment组件来操作。那么这种做法的好处就是可以节约系统资源的开销。这个其实也很好理解,可以很简单的去理解,fragment是寄生在activity之上的,以上面的应用做法为例,若是使用传统做法tabhost去做的话,则需要加载好几个activity这种重量级组件,而使用fragment方式再加载界面时我们系统只需要加载一个重量级activity,然后再使用轻量级fragment控件即可实现。
下面是个人负责的一个车辆信息canbus项目,效果图如下:
这边跟上面几个应用做法不同的是,我这边是将菜单控制部分放在了左边显示,然后在切换菜单时去加载不同的界面,下面说说是怎么个做法去实现的。
逻辑分析:
这边分两种方式去实现:
方式一:通过fragment
java代码实现部分如下:
BaseFragment.java:
package com.asir.viewpagerandfragment.fragement;
import android.annotation.SuppressLint;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@SuppressLint("NewApi")
public abstract class BaseFragment extends Fragment {
protected View mViewRoot;
protected Context mContext;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mViewRoot = initView(inflater);
return mViewRoot;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initData(savedInstanceState);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mContext = this.getActivity();
}
public View getRootView() {
return mViewRoot;
}
public abstract View initView(LayoutInflater inflater);
public abstract void initData(Bundle savedInstanceState);
}
写一个父类fragment然后让所有的fragment都去继承这个父类接口,在子类中去实现父类的两个方法initView(),initdata()即可,例举一个子类代码实现:
package com.asir.viewpagerandfragment.fragement;
import com.asir.viewpagerandfragment.R;
import com.asir.viewpagerandfragment.adapter.CarTroubleCanACAdapter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ListView;
public class CarTroubleCanACFragment extends BaseFragment {
private CarTroubleCanACAdapter mCanACAdapter;
private ListView mListView;
// 空调故障列表数据
private int[] mCarTroubleCanACInfos;
public static final int mCurrFragmentID = 6;
@Override
public View initView(LayoutInflater inflater) {
return (View) inflater.inflate(R.layout.list_view, null);
}
@Override
public void initData(Bundle savedInstanceState) {
String[] leftStr = mContext.getResources().getStringArray(R.array.car_trouble_item6_list_left);
mCanACAdapter = new CarTroubleCanACAdapter(mContext, leftStr);
mListView = (ListView) mViewRoot.findViewById(R.id.list_view);
mListView.setAdapter(mCanACAdapter);
initListener();
}
private void initListener() {
}
private void canDataCallBack(Message msg) {
int id = msg.what;
if (mCurrFragmentID == id) {
mCarTroubleCanACInfos = (int[]) msg.obj;
mCanACAdapter.setRightData(mCarTroubleCanACInfos);
}
}
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
canDataCallBack(msg);
}
};
具体的请下载demo源码分析之;那么使用方式如下:
CarTroubleActivity.java类实现:
package com.asir.viewpagerandfragment;
import com.asir.viewpagerandfragment.fragement.BaseFragment;
import com.asir.viewpagerandfragment.fragement.CarTroubleCanACFragment;
import com.asir.viewpagerandfragment.fragement.CarTroubleCanBMSFragment;
import com.asir.viewpagerandfragment.fragement.CarTroubleCanChargerFragment;
import com.asir.viewpagerandfragment.fragement.CarTroubleCanDCDCFragment;
import com.asir.viewpagerandfragment.fragement.CarTroubleCanESPFragment;
import com.asir.viewpagerandfragment.fragement.CarTroubleCanPMSMFragment;
import com.asir.viewpagerandfragment.fragement.CarTroubleVehicleFragment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
@SuppressLint("NewApi")
/**
* 汽车故障
*
* @author Administrator
*/
public class CarTroubleActivity extends Activity {
private FragmentManager mFragmentManager;
private RadioGroup mRadioGroupCenterItems;
private RadioButton mRadioCartroubleItem0;
private RadioButton mRadioCartroubleItem1;
private RadioButton mRadioCartroubleItem2;
private RadioButton mRadioCartroubleItem3;
private RadioButton mRadioCartroubleItem4;
private RadioButton mRadioCartroubleItem5;
private RadioButton mRadioCartroubleItem6;
public static final int mItemsPosition0 = 0;
public static final int mItemsPosition1 = 1;
public static final int mItemsPosition2 = 2;
public static final int mItemsPosition3 = 3;
public static final int mItemsPosition4 = 4;
public static final int mItemsPosition5 = 5;
public static final int mItemsPosition6 = 6;
public static final int mItemsPosition0_Column = 4;
public static final int mItemsPosition1_Column = 5;
public static final int mItemsPosition2_Column = 6;
public static final int mItemsPosition3_Column = 7;
public static final int mItemsPosition4_Column = 8;
public static final int mItemsPosition5_Column = 9;
public static final int mItemsPosition6_Column = 10;
private BaseFragment mCarTroubleVehicleFragment;
private BaseFragment mCarTroubleCanBMSFragment;
private BaseFragment mCarTroubleCanPMSMFragment;
private BaseFragment mCarTroubleCanDCDCFragment;
private BaseFragment mCarTroubleCanChargerFragment;
private BaseFragment mCarTroubleCanESPFragment;
private BaseFragment mCarTroubleCanACFragment;
private final String mCarTroubleVehicleFragmentTAG = "item0_tag";
private final String mCarTroubleCanBMSFragmentTAG = "item1_tag";
private final String mCarTroubleCanPMSMFragmentTAG = "item2_tag";
private final String mCarTroubleCanDCDCFragmentTAG = "item3_tag";
private final String mCarTroubleCanChargerFragmentTAG = "item4_tag";
private final String mCarTroubleCanESPFragmentTAG = "item5_tag";
private final String mCarTroubleCanACFragmentTAG = "item6_tag";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.car_trouble);
isSaveFragment(savedInstanceState);
initView();
initData();
initListener();
}
/**
* 解决Fragment界面重叠问题
*
* @param savedInstanceState
*/
private void isSaveFragment(Bundle savedInstanceState) {
mFragmentManager = getFragmentManager();
if (savedInstanceState != null) {
mCarTroubleVehicleFragment = (BaseFragment) mFragmentManager
.findFragmentByTag(mCarTroubleVehicleFragmentTAG);
mCarTroubleCanBMSFragment = (BaseFragment) mFragmentManager.findFragmentByTag(mCarTroubleCanBMSFragmentTAG);
mCarTroubleCanPMSMFragment = (BaseFragment) mFragmentManager
.findFragmentByTag(mCarTroubleCanPMSMFragmentTAG);
mCarTroubleCanDCDCFragment = (BaseFragment) mFragmentManager
.findFragmentByTag(mCarTroubleCanDCDCFragmentTAG);
mCarTroubleCanChargerFragment = (BaseFragment) mFragmentManager
.findFragmentByTag(mCarTroubleCanChargerFragmentTAG);
mCarTroubleCanESPFragment = (BaseFragment) mFragmentManager.findFragmentByTag(mCarTroubleCanESPFragmentTAG);
mCarTroubleCanACFragment = (BaseFragment) mFragmentManager.findFragmentByTag(mCarTroubleCanACFragmentTAG);
}
}
@Override
/**
* 实现这个方法,并注释掉下面这行代码可以解决Fragment界面重叠问题
*/
protected void onSaveInstanceState(Bundle outState) {
// super.onSaveInstanceState(outState);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
// System.gc();
}
private void initView() {
mRadioGroupCenterItems = (RadioGroup) findViewById(R.id.rg_center_car_trouble_items);
mRadioCartroubleItem0 = (RadioButton) findViewById(R.id.car_trouble_item0);
mRadioCartroubleItem1 = (RadioButton) findViewById(R.id.car_trouble_item1);
mRadioCartroubleItem2 = (RadioButton) findViewById(R.id.car_trouble_item2);
mRadioCartroubleItem3 = (RadioButton) findViewById(R.id.car_trouble_item3);
mRadioCartroubleItem4 = (RadioButton) findViewById(R.id.car_trouble_item4);
mRadioCartroubleItem5 = (RadioButton) findViewById(R.id.car_trouble_item5);
mRadioCartroubleItem6 = (RadioButton) findViewById(R.id.car_trouble_item6);
}
private void initData() {
// 先初始化第一个item里面的 内容
FragmentTransaction transaction = mFragmentManager.beginTransaction();
if (mCarTroubleVehicleFragment == null) {
mCarTroubleVehicleFragment = new CarTroubleVehicleFragment();
transaction.add(R.id.content_view, mCarTroubleVehicleFragment);
}
transaction.commit();
}
private void initListener() {
mRadioGroupCenterItems.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
hideFragments(transaction);
switch (checkedId) {
case R.id.car_trouble_item0:
if (mCarTroubleVehicleFragment == null) {
mCarTroubleVehicleFragment = new CarTroubleVehicleFragment();
transaction.add(R.id.content_view, mCarTroubleVehicleFragment, mCarTroubleVehicleFragmentTAG);
} else {
transaction.show(mCarTroubleVehicleFragment);
}
break;
case R.id.car_trouble_item1:
if (mCarTroubleCanBMSFragment == null) {
mCarTroubleCanBMSFragment = new CarTroubleCanBMSFragment();
transaction.add(R.id.content_view, mCarTroubleCanBMSFragment, mCarTroubleCanBMSFragmentTAG);
} else {
transaction.show(mCarTroubleCanBMSFragment);
}
break;
case R.id.car_trouble_item2:
if (mCarTroubleCanPMSMFragment == null) {
mCarTroubleCanPMSMFragment = new CarTroubleCanPMSMFragment();
transaction.add(R.id.content_view, mCarTroubleCanPMSMFragment, mCarTroubleCanPMSMFragmentTAG);
} else {
transaction.show(mCarTroubleCanPMSMFragment);
}
break;
case R.id.car_trouble_item3:
if (mCarTroubleCanDCDCFragment == null) {
mCarTroubleCanDCDCFragment = new CarTroubleCanDCDCFragment();
transaction.add(R.id.content_view, mCarTroubleCanDCDCFragment, mCarTroubleCanDCDCFragmentTAG);
} else {
transaction.show(mCarTroubleCanDCDCFragment);
}
break;
case R.id.car_trouble_item4:
if (mCarTroubleCanChargerFragment == null) {
mCarTroubleCanChargerFragment = new CarTroubleCanChargerFragment();
transaction.add(R.id.content_view, mCarTroubleCanChargerFragment,
mCarTroubleCanChargerFragmentTAG);
} else {
transaction.show(mCarTroubleCanChargerFragment);
}
break;
case R.id.car_trouble_item5:
if (mCarTroubleCanESPFragment == null) {
mCarTroubleCanESPFragment = new CarTroubleCanESPFragment();
transaction.add(R.id.content_view, mCarTroubleCanESPFragment, mCarTroubleCanESPFragmentTAG);
} else {
transaction.show(mCarTroubleCanESPFragment);
}
break;
case R.id.car_trouble_item6:
if (mCarTroubleCanACFragment == null) {
mCarTroubleCanACFragment = new CarTroubleCanACFragment();
transaction.add(R.id.content_view, mCarTroubleCanACFragment, mCarTroubleCanACFragmentTAG);
} else {
transaction.show(mCarTroubleCanACFragment);
}
break;
}
transaction.commit();
}
});
}
private void hideFragments(FragmentTransaction transaction) {
if (mCarTroubleVehicleFragment != null)
transaction.hide(mCarTroubleVehicleFragment);
if (mCarTroubleCanBMSFragment != null)
transaction.hide(mCarTroubleCanBMSFragment);
if (mCarTroubleCanPMSMFragment != null)
transaction.hide(mCarTroubleCanPMSMFragment);
if (mCarTroubleCanDCDCFragment != null)
transaction.hide(mCarTroubleCanDCDCFragment);
if (mCarTroubleCanChargerFragment != null)
transaction.hide(mCarTroubleCanChargerFragment);
if (mCarTroubleCanESPFragment != null)
transaction.hide(mCarTroubleCanESPFragment);
if (mCarTroubleCanACFragment != null)
transaction.hide(mCarTroubleCanACFragment);
}
}
这边我们在使用fragment这种做法时,在切换界面时不要重复去加载界面,也不要去replayce重新加载,这种会很浪费资源,浪费时间;最好的做法就是将已经加载过的fragment再切换界面时将其隐藏,然后再使用fragment实现方式时会有这种问题出现,估计用得多人都有这个体会了,就是fragment的界面重叠问题,那么解决方法如下;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.car_trouble);
isSaveFragment(savedInstanceState);
initView();
initData();
initListener();
}
/**
* 解决Fragment界面重叠问题
*
* @param savedInstanceState
*/
private void isSaveFragment(Bundle savedInstanceState) {
mFragmentManager = getFragmentManager();
if (savedInstanceState != null) {
mCarTroubleVehicleFragment = (BaseFragment) mFragmentManager
.findFragmentByTag(mCarTroubleVehicleFragmentTAG);
mCarTroubleCanBMSFragment = (BaseFragment) mFragmentManager.findFragmentByTag(mCarTroubleCanBMSFragmentTAG);
mCarTroubleCanPMSMFragment = (BaseFragment) mFragmentManager
.findFragmentByTag(mCarTroubleCanPMSMFragmentTAG);
mCarTroubleCanDCDCFragment = (BaseFragment) mFragmentManager
.findFragmentByTag(mCarTroubleCanDCDCFragmentTAG);
mCarTroubleCanChargerFragment = (BaseFragment) mFragmentManager
.findFragmentByTag(mCarTroubleCanChargerFragmentTAG);
mCarTroubleCanESPFragment = (BaseFragment) mFragmentManager.findFragmentByTag(mCarTroubleCanESPFragmentTAG);
mCarTroubleCanACFragment = (BaseFragment) mFragmentManager.findFragmentByTag(mCarTroubleCanACFragmentTAG);
}
}
@Override
/**
* 实现这个方法,并注释掉下面这行代码可以解决Fragment界面重叠问题
*/
protected void onSaveInstanceState(Bundle outState) {
// super.onSaveInstanceState(outState);
}
方式二通过viewpager:
代码实现部分如下:
个人这个车辆信息应用为什么要采用这种方式去实现呢,因为viewpager比fragment实现方式显得更加轻量级一些,而且可以避免应用重启时的界面重叠的问题。选择加载一个fragment然后用viewpager显示多个页面。
BasePage.java代码如下:
package com.asir.viewpagerandfragment.pages;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
public abstract class BasePage {
protected Context mContext;
protected View mViewRoot;
/**
* 1 。画界面 2 初始化数据
*/
public BasePage(Context ct) {
this.mContext = ct;
LayoutInflater inflater = (LayoutInflater) ct.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mViewRoot = initView(inflater);
initData();
}
public View getRootView() {
return mViewRoot;
}
public abstract View initView(LayoutInflater inflater);
public abstract void initData();
}
这边写一个抽象父类pagerBean类(这边Bean指的是一个对象封装),提供两个抽象方法initView(),一个initData(),再提供一各getRootView()返回当前加载的视图xml界面,然后让所有的子viewpagerBean类去继承这个Basepager类去实现两个抽象方法;然后在使用的时候用List队列添加子类pagerBean,在PagerAdapter加载时添加pagerBean之前加载的view视图即可,使用方式具体代码如下:
MyCarHomeFragment.java
package com.asir.viewpagerandfragment.fragement;
import java.util.ArrayList;
import java.util.List;
import com.asir.viewpagerandfragment.R;
import com.asir.viewpagerandfragment.pages.BasePage;
import com.asir.viewpagerandfragment.pages.MyCarBatteryInfoPage;
import com.asir.viewpagerandfragment.pages.MyCarCarStatusPage;
import com.asir.viewpagerandfragment.pages.MyCarMonomerBatteryPage;
import com.asir.viewpagerandfragment.pages.MyCarMotorInfoPage;
import com.asir.viewpagerandfragment.view.MyCarViewPager;
import com.asir.viewpagerandfragment.view.MyCarViewPager.OnPageChangeListener;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.RadioButton;
import android.widget.RadioGroup;
public class MyCarHomeFragment extends BaseFragment implements OnClickListener {
private ViewGroup mViewRoot;
private MyCarViewPager mViewPager;
private RadioGroup mRadioGroupBottoms;
private List mPageList = new ArrayList();
private MyCarCarStatusPage mMyCarCarStatusPage;
private MyCarBatteryInfoPage mMyCarBatteryInfoPage;
private MyCarMotorInfoPage mMyCarMotorInfoPage;
private MyCarMonomerBatteryPage mMyCarMonomerBatteryPage;
@Override
public View initView(LayoutInflater inflater) {
mViewRoot = (ViewGroup) inflater.inflate(R.layout.my_car_home_fragment, null);
mRadioGroupBottoms = (RadioGroup) mViewRoot.findViewById(R.id.main_radio);
mViewPager = (MyCarViewPager) mViewRoot.findViewById(R.id.viewpager);
initPagesView();
return mViewRoot;
}
@Override
public void initData(Bundle savedInstanceState) {
initListener();
}
private void initListener() {
int childCount = mRadioGroupBottoms.getChildCount();
for (int i = 0; i < childCount; i++) {
mRadioGroupBottoms.getChildAt(i).setOnClickListener(MyCarHomeFragment.this);
}
mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
RadioButton rb = (RadioButton) mRadioGroupBottoms.getChildAt(position);
rb.setChecked(true);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private void initPagesView() {
mMyCarCarStatusPage = new MyCarCarStatusPage(mContext);
mMyCarBatteryInfoPage = new MyCarBatteryInfoPage(mContext);
mMyCarMotorInfoPage = new MyCarMotorInfoPage(mContext);
mMyCarMonomerBatteryPage = new MyCarMonomerBatteryPage(mContext);
mPageList.add(mMyCarCarStatusPage);
mPageList.add(mMyCarBatteryInfoPage);
mPageList.add(mMyCarMotorInfoPage);
mPageList.add(mMyCarMonomerBatteryPage);
HomePageAdapter adapter = new HomePageAdapter(mContext, mPageList);
mViewPager.setAdapter(adapter);
}
class HomePageAdapter extends PagerAdapter {
private Context ct;
private List list;
public HomePageAdapter(Context ct, List list) {
this.ct = ct;
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// super.destroyItem(container, position, object);
((MyCarViewPager) container).removeView(list.get(position).getRootView());
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
((MyCarViewPager) container).addView(list.get(position).getRootView(), 0);
return list.get(position).getRootView();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.car_status:
mViewPager.setCurrentItem(0, false);
break;
case R.id.battery_info:
mViewPager.setCurrentItem(1, false);
break;
case R.id.motor_info:
mViewPager.setCurrentItem(2, false);
break;
case R.id.monomer_battery:
mViewPager.setCurrentItem(3, false);
break;
}
}
}
有需要的朋友下载demo源码修改修改即可仿写微信,支付宝等大致布局样式,两种方式都可以实现,喜欢哪种就用哪种就好了。
源码点击下载