标签:模仿知乎android app二 toolbar drawerlayout fragment的使用
这一次本人分享的是模仿知乎Android APP这个类型的,还有网易新闻等,他们都菜单界面等挺相似的。
我使用的是Material Design中提倡的app bar。使用ToolBar+DrawerLayout+Fragment实现,大家也可以在Fragment里面嵌套ViewPager这样使得Fragment包含一个ViewPager,ViewPager包含更多的Faragment去显示内容。
这个Demo的大概功能叙述:
使用ToolBar,然后会有一个左侧菜单,使用的是Fragment来实现,然后点击菜单的时候会显示不同的Fragment ,而且该fragment不会掩掉toolbar,不会像上一个案例一样每点击一次都去使用一个新的Activity然后把toolbar掩盖,大家可以去看看那篇blog:
模仿知乎APP一 。、
主要的思路:
使用ToolBar的一些细节就是需要继承AppCompatActivity(V7包下),使用的ToolBar也是V7包下的,那么环境之类这里也不详细说了,然后需要去重新写一个style Apptheme,去掉默认的ActionBar。再然后在布局文件中头部使用ToolBar,然后在使用一个DrawerLayout,他的第一个View是内容区域,我们使用一个FrameLayout,第二个view是左侧菜单,我们也是用一个FrameLayout,这样,我们就可以做到重用内容区域,可以使用不同的Fragment放在第二个内容区域中。
具体还是开代码实现吧:
项目架构:
它包含3个Fragment去显示内容区域,一个MainActivity,然后还有一个LeftFragment以及对应的Adapter
先看布局文件:
主布局文件,就像上面,没什么好讲的
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res/com.example.mytoolbar_04"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical"
tools:context="com.example.mytoolbar_04.MainActivity" >
<android.support.v7.widget.Toolbar
android:id="@+id/id_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_toc_white_24dp"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:title="APP Title" />
<android.support.v4.widget.DrawerLayout
android:id="@+id/id_drawerlayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="@+id/id_content_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
<FrameLayout
android:id="@+id/id_left_menu_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="left"
android:background="#ffffff" >
</FrameLayout>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>然后是左侧菜单的ListView的布局文件,一个图片+文字作为一个item,也就这样
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center_vertical"
android:paddingRight="16dp"
>
<ImageView
android:layout_marginLeft="16dp"
android:id="@+id/id_item_icon"
android:src="@drawable/music_36px"
android:layout_marginRight="8dp"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/id_item_title"
android:layout_marginLeft="72dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#64000000"
android:textSize="16sp"
android:text="@string/hello_world"
android:layout_gravity="center_vertical"
/>
</FrameLayout>然后是style文件:
他是被清单文件中的application引用,他的主题需要是android:Theme.Light,然后加入有values-v14等包,它里面的style文件也需要更改,否则可能出错
<resources>
<style name="AppBaseTheme" parent="android:Theme.Light">
</style>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/material_blue_500</item>
<item name="colorPrimaryDark">@color/material_blue_700</item>
<item name="colorAccent">@color/material_green_A200</item>
</style>
</resources>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.example.mytoolbar_04.MainActivity" >
<!-- 总是显示 -->
<item
android:id="@+id/id_action_refreash"
android:icon="@drawable/ic_cached_white_24dp"
android:orderInCategory="100"
android:title="@string/action_refreash"
app:showAsAction="always"/>
<!-- 总是显示 -->
<item
android:id="@+id/id_action_delete"
android:icon="@drawable/ic_delete_white_24dp"
android:orderInCategory="100"
android:title="@string/action_delete"
app:showAsAction="always"/>
<!-- 总是显示 -->
<item
android:id="@+id/id_action_favorite"
android:icon="@drawable/ic_favorite_outline_white_24dp"
android:orderInCategory="100"
android:title="@string/action_favorite"
app:showAsAction="always"/>
<!-- 不显示在ActionBar上 -->
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings"/>
</menu>首先是,内容区域,我的三个Fragment都是类似的,所以只贴出一个,他显示一个TextView
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
public class FirstFragment extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
TextView tv = new TextView(getActivity());
LinearLayout.LayoutParams lp = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
tv.setLayoutParams(lp);
tv.setTextSize(50);
tv.setText("第一个Fragment");
return tv;
}
}然后是MenuItem.java,他domain类,是对右侧菜单的item的一些属性的集合
public MenuItem(String text, boolean isSelected, int icon, int iconSelected)
{
this.text = text; //显示的文字
this.isSelected = isSelected; //是否被选中
this.icon = icon; //他的图标
this.iconSelected = iconSelected; //选中的图标
}
boolean isSelected;
String text;
int icon;
int iconSelected;
}
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
public class LeftMenuFragment extends ListFragment
{
private static final int SIZE_MENU_ITEM = 3;//菜单总数
private MenuItem[] mItems = new MenuItem[SIZE_MENU_ITEM];
private LeftMenuAdapter mAdapter;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
MenuItem menuItem = null;
for (int i = 0; i < SIZE_MENU_ITEM; i++)
{
menuItem = new MenuItem(getResources().getStringArray(R.array.array_left_menu)[i], false,
R.drawable.music_36px, R.drawable.music_36px_light);
mItems[i] = menuItem;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
setListAdapter(mAdapter = new LeftMenuAdapter(getActivity(), mItems));
}
@Override
public void onListItemClick(ListView l, View v, int position, long id)
{
super.onListItemClick(l, v, position, id);
if (mMenuItemSelectedListener != null)
{
mMenuItemSelectedListener.menuItemSelected(
((MenuItem) getListAdapter().getItem(position)).text, position);// 发生点击事件,传递参数给Activity处理
}
mAdapter.setSelected(position);
}
// 点击监听器
public interface OnMenuItemSelectedListener
{
/**
* @param title 被点击listview的标题
* @param position 被点击ListView的position
*/
void menuItemSelected(String title, int position);
}
private OnMenuItemSelectedListener mMenuItemSelectedListener; // 监听ListView点击之后发生的事情,用于与Activity交互
public void setOnMenuItemSelectedListener(OnMenuItemSelectedListener menuItemSelectedListener)
{
this.mMenuItemSelectedListener = menuItemSelectedListener;
}
}
他的适配器:适配器就不多说,主要是有一个setSelected方法,他的作用是去设置被单击的item的一些背景,icon
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class LeftMenuAdapter extends ArrayAdapter<MenuItem>
{
private LayoutInflater mInflater;
private int mSelected;
public LeftMenuAdapter(Context context, MenuItem[] objects)
{
super(context, -1, objects);
mInflater = LayoutInflater.from(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
if (convertView == null)
{
convertView = mInflater.inflate(R.layout.item_left_menu, parent, false);
}
ImageView iv = (ImageView) convertView.findViewById(R.id.id_item_icon);
TextView title = (TextView) convertView.findViewById(R.id.id_item_title);
title.setText(getItem(position).text);
iv.setImageResource(getItem(position).icon);
convertView.setBackgroundColor(Color.TRANSPARENT);
// 假如是当前的item,则是去设置他对对应的backgroundColor和新的drawable,以区分其他的
if (position == mSelected)
{
iv.setImageResource(getItem(position).iconSelected);
convertView.setBackgroundColor(getContext().getResources().getColor(
R.color.state_menu_item_selected));
}
return convertView;
}
/**
* @param position点击的时候item的位置
*/
public void setSelected(int position)
{
this.mSelected = position;
notifyDataSetChanged();
}
}然后,是我们最重要的MainActivity了,里面都有注释,应该都能看懂的了~~,他的一些功能,初始化UI,ToolBar,然后需要在OnCreate方法中选中首个需要显示的title和Fragment,然后需要注意的是显示在toolbar上的标题应该是跟ListVIew被单击的item的title是一样的。然后单击事件的前提是当前LeftMenuFragment是展开的,单击之后需要先把所有的Fragment先隐藏,再去判断那个Fragment需要显示再去显示。再处理一下ToolBar的菜单的点击事件,这里点击之后都会显示一份Toast。再处理按下物理返回键的时候应该做出的行为,当是菜单展开的时候关闭菜单而不是关闭应用,然后没有菜单展开才是关闭应用。
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
import com.example.mytoolbar_04.fragment.FirstFragment;
import com.example.mytoolbar_04.fragment.SecondFragment;
import com.example.mytoolbar_04.fragment.ThirdFragment;
public class MainActivity extends AppCompatActivity
{
private ActionBarDrawerToggle mActionBarDrawerToggle;
private DrawerLayout mDrawerLayout;// 包括左侧菜单和内容区域
private Toolbar mToolbar;// toolbar
private LeftMenuFragment mLeftMenuFragment;// 左侧菜单
private String mTitle;
private boolean flag = false;// 左侧菜单是否展开的标志
private static final String KEY_TITLLE = "key_title";
private FirstFragment firstFragment; //对应三个不同的内容区域,第一个
private SecondFragment secondFragment;//第二个
private ThirdFragment thirdFragment;//第三个
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initToolBar();
initViews();
// 重置页面的也就是ToolBar的标题
restoreTitle(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();// v4包
mLeftMenuFragment = (LeftMenuFragment) fm.findFragmentById(R.id.id_left_menu_container);
if (mLeftMenuFragment == null)
{
mLeftMenuFragment = new LeftMenuFragment();
fm.beginTransaction().add(R.id.id_left_menu_container, mLeftMenuFragment).commit();
}
// 进行对leftFragment的点击事件监听,需要的是此时leftFragment这时候是展开的,
// 然后点击完成需要关闭该LeftMenuFragment,显示被点击的item对应的Fragment
mLeftMenuFragment
.setOnMenuItemSelectedListener(new LeftMenuFragment.OnMenuItemSelectedListener()
{
@Override
public void menuItemSelected(String title, int position)
{
showSelectedFragment(position);
mTitle = title;
mToolbar.setTitle(mTitle);// 设置toolbar的文字
mDrawerLayout.closeDrawer(Gravity.LEFT); // 关闭菜单
}
});
// 设置默认其中的Fragment
showSelectedFragment(0);
}
/**
* 当点击LeftFragment时候选择需要显示的内容Fragment
* @param position
*/
protected void showSelectedFragment(int position)
{
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
hideFragment(fragmentTransaction);
switch (position)
{
case 0:
if (firstFragment == null)
{
firstFragment = new FirstFragment();
fragmentTransaction.add(R.id.id_content_container, firstFragment);
} else
{
fragmentTransaction.show(firstFragment);
}
break;
case 1:
if (secondFragment == null)
{
secondFragment = new SecondFragment();
fragmentTransaction.add(R.id.id_content_container, secondFragment);
} else
{
fragmentTransaction.show(secondFragment);
}
break;
case 2:
if (thirdFragment == null)
{
thirdFragment = new ThirdFragment();
fragmentTransaction.add(R.id.id_content_container, thirdFragment);
} else
{
fragmentTransaction.show(thirdFragment);
}
break;
}
fragmentTransaction.commit();
}
/**
* 每一次显示Fragment之前都先去隐藏Fragment
* @param fragmentTransaction
*/
protected void hideFragment(FragmentTransaction fragmentTransaction)
{
if (firstFragment != null)
{
fragmentTransaction.hide(firstFragment);
}
if (secondFragment != null)
{
fragmentTransaction.hide(secondFragment);
}
if (thirdFragment != null)
{
fragmentTransaction.hide(thirdFragment);
}
}
/**
* 恢复标题,使得toolbar中的文字与LeftMenuFragment上的ListVIew文字一样
* @param savedInstanceState
*/
private void restoreTitle(Bundle savedInstanceState)
{
if (savedInstanceState != null)// 存在的时候,把标题读出了,显示
mTitle = savedInstanceState.getString(KEY_TITLLE);
if (TextUtils.isEmpty(mTitle))// 如何不存在,就像是第一次点击来应用的时候,显示主页面
{
mTitle = getResources().getStringArray(R.array.array_left_menu)[0];
}
mToolbar.setTitle(mTitle);
}
/*
* 该方法执行时期为用户点击了home键长时间没有返回主界面或者是切换竖横屏的时候,
* 这时候会保存对于的fragment的title,下载被onCreate方法中用到 一定需要重写,或者可能出现文字的重叠(由于Fragment的重叠)
*/
@Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putString(KEY_TITLLE, mTitle);
}
/**
* 初始化ToolBar
*/
private void initToolBar()
{
Toolbar toolbar = mToolbar = (Toolbar) findViewById(R.id.id_toolbar);
toolbar.setTitle(getResources().getStringArray(R.array.array_left_menu)[0]);
setSupportActionBar(toolbar);// 需要在设置title之后才执行
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener()
{
@Override
public boolean onMenuItemClick(android.view.MenuItem arg0)
{
int event = arg0.getItemId();
switch (event)
{
case R.id.id_action_refreash:
showToast("您点击了刷新按钮");
return true;
case R.id.id_action_delete:
showToast("您点击了删除按钮");
return true;
case R.id.id_action_favorite:
showToast("您点击了收藏按钮");
return true;
}
return false;
}
});
}
/**
* 打印toast
* @param text需要显示的文字
*/
protected void showToast(String text)
{
Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
/*
* 创建菜单
*/
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
/**
* 初始化
*/
private void initViews()
{
mDrawerLayout = (DrawerLayout) findViewById(R.id.id_drawerlayout);
// 这个drawerListener需要对drawer的展开状态进行监听,改变他的flag
mActionBarDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar,
R.string.open, R.string.close)
{
@Override
public void onDrawerClosed(View drawerView)
{
super.onDrawerClosed(drawerView);
flag = false;
}
@Override
public void onDrawerOpened(View drawerView)
{
super.onDrawerOpened(drawerView);
flag = true;
}
};
mActionBarDrawerToggle.syncState();
mDrawerLayout.setDrawerListener(mActionBarDrawerToggle);
}
/*
* 他的一个作用是监听当前的左侧菜单是否展开,假如展开则点击时候关闭不退出应用,否则关闭应用
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (flag)
{
mDrawerLayout.closeDrawers();
return true;
}
return super.onKeyDown(keyCode, event);
}
}结果截图:
参考bolg,hyman老师的:Android 5.x Theme 与 ToolBar 实战
标签:模仿知乎android app二 toolbar drawerlayout fragment的使用
原文地址:http://blog.csdn.net/liweijie_chengxuyuan/article/details/45571333