模仿知乎Android APP二

來源:互聯網
上載者:User

標籤:模仿知乎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{@Overridepublic 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;@Overridepublic 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;}}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){return super.onCreateView(inflater, container, savedInstanceState);}@Overridepublic void onViewCreated(View view, @Nullable Bundle savedInstanceState){super.onViewCreated(view, savedInstanceState);setListAdapter(mAdapter = new LeftMenuAdapter(getActivity(), mItems));}@Overridepublic 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);}@Overridepublic 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;// toolbarprivate 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;//第三個@Overrideprotected 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對應的FragmentmLeftMenuFragment    .setOnMenuItemSelectedListener(new LeftMenuFragment.OnMenuItemSelectedListener()    {    @Override    public void menuItemSelected(String title, int position)    {    showSelectedFragment(position);mTitle = title;mToolbar.setTitle(mTitle);// 設定toolbar的文字mDrawerLayout.closeDrawer(Gravity.LEFT); // 關閉菜單}    });// 設定預設其中的FragmentshowSelectedFragment(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的重疊) */@Overrideprotected 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(){@Overridepublic 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();}/* * 建立菜單 */@Overridepublic 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的展開狀態進行監聽,改變他的flagmActionBarDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar,    R.string.open, R.string.close){@Overridepublic void onDrawerClosed(View drawerView){super.onDrawerClosed(drawerView);flag = false;}@Overridepublic void onDrawerOpened(View drawerView){super.onDrawerOpened(drawerView);flag = true;}};mActionBarDrawerToggle.syncState();mDrawerLayout.setDrawerListener(mActionBarDrawerToggle);}/* *  他的一個作用是監聽當前的左側菜單是否展開,假如展開則點擊時候關閉不退出應用,否則關閉應用 */@Overridepublic 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二

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.