码迷,mamicode.com
首页 > 移动开发 > 详细

模仿知乎Android APP二

时间:2015-05-08 09:31:34      阅读:197      评论:0      收藏:0      [点我收藏+]

标签:模仿知乎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>

ToolBar上的菜单:

<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;
}

然后是LeftMenuFragment.java类,他是左侧的菜单,用于填充DrawerLayout中的第二个View。他继承ListFragment,不需要重写onCreateView方法,监听他的item的点击事件,使用一个接口OnMenuItemSelectedListener去负责与Activity交互,然后,里面包含一个方法menuItemSelecte(String title ,int position),分别是item的标题和他在ListView的位置position

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二

标签:模仿知乎android app二   toolbar   drawerlayout   fragment的使用   

原文地址:http://blog.csdn.net/liweijie_chengxuyuan/article/details/45571333

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!