天天看點

Android 項目開發架構

    今天這篇文章,主要是為了快速搭建一個項目主體架構!

    目前好多應用的主界面都是,底部幾個切換按鈕,點選不同的按鈕,切換不同的界面,先來幾張截圖,如下,

Android 項目開發架構
Android 項目開發架構
Android 項目開發架構

這三張截圖,分别來自淘寶、京東、網易新聞,都是目前使用者使用量比較多的,并且,我在實際的項目中,用這個樣式的也比較多。那麼今天,我們就簡單實作這樣一個項目架構。

    先看2張我實作的效果圖,

Android 項目開發架構
Android 項目開發架構

這是我仿照網易新聞用戶端做的!看着效果還行!O(∩_∩)O!那麼我們就開始今天的學習。

一.建立項目;

Android 項目開發架構

二.建立布局檔案,activity_home.xml,該布局檔案代碼如下,

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/navigation_tab_ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@color/color_aaaaaa"
        android:orientation="horizontal"
        android:paddingTop="1dp"
        android:weightSum="5" >

        <LinearLayout
            android:id="@+id/id_news_ll"
            style="@style/style_navigation_tab_ll" >

            <ImageView
                android:id="@+id/id_news_iv"
                style="@style/style_navigation_tab_iv"
                android:background="@drawable/biz_navigation_tab_news_selected" />

            <TextView
                android:id="@+id/id_news_tv"
                style="@style/style_navigation_tab_tv"
                android:text="新聞"
                android:textColor="@color/color_eb413d" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/id_read_ll"
            style="@style/style_navigation_tab_ll" >

            <ImageView
                android:id="@+id/id_read_iv"
                style="@style/style_navigation_tab_iv"
                android:background="@drawable/biz_navigation_tab_read" />

            <TextView
                android:id="@+id/id_read_tv"
                style="@style/style_navigation_tab_tv"
                android:text="閱讀"
                android:textColor="@color/color_aaaaaa" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/id_va_ll"
            style="@style/style_navigation_tab_ll" >

            <ImageView
                android:id="@+id/id_va_iv"
                style="@style/style_navigation_tab_iv"
                android:background="@drawable/biz_navigation_tab_va" />

            <TextView
                android:id="@+id/id_va_tv"
                style="@style/style_navigation_tab_tv"
                android:text="視聽"
                android:textColor="@color/color_aaaaaa" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/id_topic_ll"
            style="@style/style_navigation_tab_ll" >

            <ImageView
                android:id="@+id/id_topic_iv"
                style="@style/style_navigation_tab_iv"
                android:background="@drawable/biz_navigation_tab_topic" />

            <TextView
                android:id="@+id/id_topic_tv"
                style="@style/style_navigation_tab_tv"
                android:text="話題"
                android:textColor="@color/color_aaaaaa" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/id_pc_ll"
            style="@style/style_navigation_tab_ll" >

            <ImageView
                android:id="@+id/id_pc_iv"
                style="@style/style_navigation_tab_iv"
                android:background="@drawable/biz_navigation_tab_pc" />

            <TextView
                android:id="@+id/id_pc_tv"
                style="@style/style_navigation_tab_tv"
                android:text="我"
                android:textColor="@color/color_aaaaaa" />
        </LinearLayout>
    </LinearLayout>

    <FrameLayout
        android:id="@+id/home_fl"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/navigation_tab_ll" />

</RelativeLayout>
           

底部是5個可以選擇的控件,這些布局之上是一個FrameLayout,FrameLayout是用來當點選底部不同的控件顯示不同的布局。這個很簡單!

    我們這個裡面用到Fragment(當你點選不同的控件時,顯示的是不同Fragment),這是Android3.0後給出的,它很友善的解決了在pad或者大螢幕上app适配的問題(也就是說,隻要你在代碼中控制,那麼一套代碼就可以在手機、平闆等裝置上都可以适用,并且顯出的效果會根據裝置有所調整),官方也大力推薦我們在項目中使用它。現在v4包裡面已經有Fragment,當我們向下相容時,導入v4包就可以了。

    接着,我們需要建立5個fragment_*.xml布局檔案,這5個布局檔案都差不多,隻是顯示的文字不一樣,是以,那看其中一個的布局,fragment_news.xml,代碼如下,

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="新聞"
                android:textSize="20sp"
                android:textColor="@color/color_eb413d" />

</RelativeLayout>
           

該布局就隻顯示一個TextView,fragment_*.xml其他的布局都差不多。

三.建立Fragment,我們就隻看看NewsFragment的實作,

/**
 * 新聞
 */
public class NewsFragment extends Fragment {

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		View view=inflater.inflate(R.layout.fragment_news, container, false);
		return view;
	}
	
	/* (non-Javadoc)
	 * 當Fragment隐藏或者顯示的時候調用
	 * @see android.support.v4.app.Fragment#onHiddenChanged(boolean)
	 */
	@Override
	public void onHiddenChanged(boolean hidden) {
		// TODO Auto-generated method stub
		super.onHiddenChanged(hidden);
		if(hidden){// 不在最前端界面顯示
			
		}else{// 重新顯示到最前端中
			
		}
	}
}
           

onCreateView(),這個方法是當Fragment加載布局時調用的,onHiddenChanged(),該方法當Fragment隐藏或者顯示的時候調用(我們在某些時候每次當顯示Fragment時都應該顯示最新的資料就可以用,詳細的可以看這篇文章:Fragment hide,show方法後,會調用什麼方法)。其他的Fragment的實作和這個都類似,唯一不一樣的地方就是加載的布局檔案不一樣。

四.建立Activity,我在項目中,定義了一個Activity基類,BaseActivity,,讓它繼承FragmentActivity

/**
 * activity基類
 */
public class BaseActivity extends FragmentActivity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView();
		initView();
		setListener();
		loadData();
	}

	/**
	 * 加載布局
	 */
	protected void setContentView() {
	}

	/**
	 * 綁定控件
	 */
	protected void initView() {
	}

	/**
	 * 設定監聽事件
	 */
	protected void setListener() {
	}

	/**
	 * 加載資料
	 */
	protected void loadData() {
	}

}

           

定義了一些方法,把代碼分類。我們建立HomeAcivity,繼承BaseActivity,代碼如下,

/**
 * 主布局
 */
@SuppressWarnings("deprecation")
public class HomeAcivity extends BaseActivity implements OnClickListener {

	private FragmentManager fragmentManager;// Fragment管理
	private NewsFragment newsFragment;//新聞
	private ReadFragment readFragment;//閱讀
	private VaFragment vaFragment;//視聽
	private TopicFragment topicFragment;//話題
	private MemberFragment memberFragment;//我

	private ImageView newsIv;
	private ImageView readIv;
	private ImageView vaIv;
	private ImageView topicIv;
	private ImageView memberIv;

	private TextView newsTv;
	private TextView readTv;
	private TextView vaTv;
	private TextView topicTv;
	private TextView memberTv;
	private String tag = "0";//目前位置的辨別
	private boolean isAppExit; // app退出标志位
	public static final int APPEXIT = -1;//

	@Override
	protected void setContentView() {
		setContentView(R.layout.activity_home);
	}

	@Override
	protected void initView() {
		newsIv = (ImageView) findViewById(R.id.id_news_iv);
		readIv = (ImageView) findViewById(R.id.id_read_iv);
		vaIv = (ImageView) findViewById(R.id.id_va_iv);
		topicIv = (ImageView) findViewById(R.id.id_topic_iv);
		memberIv = (ImageView) findViewById(R.id.id_pc_iv);

		newsTv = (TextView) findViewById(R.id.id_news_tv);
		readTv = (TextView) findViewById(R.id.id_read_tv);
		vaTv = (TextView) findViewById(R.id.id_va_tv);
		topicTv = (TextView) findViewById(R.id.id_topic_tv);
		memberTv = (TextView) findViewById(R.id.id_pc_tv);
	}

	@Override
	protected void setListener() {
		findViewById(R.id.id_news_ll).setOnClickListener(this);
		findViewById(R.id.id_read_ll).setOnClickListener(this);
		findViewById(R.id.id_va_ll).setOnClickListener(this);
		findViewById(R.id.id_topic_ll).setOnClickListener(this);
		findViewById(R.id.id_pc_iv).setOnClickListener(this);

		newsIv.setOnClickListener(this);
		readIv.setOnClickListener(this);
		vaIv.setOnClickListener(this);
		topicIv.setOnClickListener(this);
		memberIv.setOnClickListener(this);
	}

	@Override
	protected void loadData() {
		fragmentManager = getSupportFragmentManager();
		setTabSelection(0);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.id_news_ll:
		case R.id.id_news_iv:
			setTabSelection(0);
			break;
		case R.id.id_read_ll:
		case R.id.id_read_iv:
			setTabSelection(1);
			break;
		case R.id.id_va_ll:
		case R.id.id_va_iv:
			setTabSelection(2);
			break;
		case R.id.id_topic_ll:
		case R.id.id_topic_iv:
			setTabSelection(3);
			break;
		case R.id.id_pc_ll:
		case R.id.id_pc_iv:
			setTabSelection(4);
			break;
		default:
			break;
		}
	}

	/**
	 * @param index
	 */
	private void setTabSelection(int index) {
		// 每次選中之前先清除掉上次的選中狀态
		clearSelection();
		// 開啟一個Fragment事務
		FragmentTransaction transaction = fragmentManager.beginTransaction();
		// 先隐藏掉所有的Fragment,以防止有多個Fragment顯示在界面上的情況
		hideFragments(transaction);
		switch (index) {
		case 0:
			tag = "0";
			newsIv.setBackgroundResource(R.drawable.biz_navigation_tab_news_selected);
			newsTv.setTextColor(getResources().getColor(R.color.color_eb413d));
			if (newsFragment == null) {
				// 如果BrandSaleFragment為空,則建立一個并添加到界面上
				newsFragment = new NewsFragment();
				// mallFragment.setArguments(bundle);
				transaction.add(R.id.home_fl, newsFragment);
			} else {
				// 如果MessageFragment不為空,則直接将它顯示出來
				transaction.show(newsFragment);
			}
			break;
		case 1:
			tag = "1";
			readIv.setBackgroundResource(R.drawable.biz_navigation_tab_read_selected);
			readTv.setTextColor(getResources().getColor(R.color.color_eb413d));
			if (readFragment == null) {
				// 如果BrandSaleFragment為空,則建立一個并添加到界面上
				readFragment = new ReadFragment();
				// mallFragment.setArguments(bundle);
				transaction.add(R.id.home_fl, readFragment);
			} else {
				// 如果MessageFragment不為空,則直接将它顯示出來
				transaction.show(readFragment);
			}
			break;
		case 2:
			tag = "2";
			vaIv.setBackgroundResource(R.drawable.biz_navigation_tab_va_selected);
			vaTv.setTextColor(getResources().getColor(R.color.color_eb413d));
			if (vaFragment == null) {
				// 如果BrandSaleFragment為空,則建立一個并添加到界面上
				vaFragment = new VaFragment();
				// mallFragment.setArguments(bundle);
				transaction.add(R.id.home_fl, vaFragment);
			} else {
				// 如果MessageFragment不為空,則直接将它顯示出來
				transaction.show(vaFragment);
			}
			break;
		case 3:
			tag = "3";
			topicIv.setBackgroundResource(R.drawable.biz_navigation_tab_topic_selected);
			topicTv.setTextColor(getResources().getColor(R.color.color_eb413d));
			if (topicFragment == null) {
				// 如果BrandSaleFragment為空,則建立一個并添加到界面上
				topicFragment = new TopicFragment();
				// mallFragment.setArguments(bundle);
				transaction.add(R.id.home_fl, topicFragment);
			} else {
				// 如果MessageFragment不為空,則直接将它顯示出來
				transaction.show(topicFragment);
			}
			break;
		case 4:
			tag = "4";
			memberIv.setBackgroundResource(R.drawable.biz_navigation_tab_pc_selected);
			memberTv.setTextColor(getResources().getColor(R.color.color_eb413d));
			if (memberFragment == null) {
				// 如果BrandSaleFragment為空,則建立一個并添加到界面上
				memberFragment = new MemberFragment();
				// mallFragment.setArguments(bundle);
				transaction.add(R.id.home_fl, memberFragment);
			} else {
				// 如果MessageFragment不為空,則直接将它顯示出來
				transaction.show(memberFragment);
			}
			break;
		}
		transaction.commit();
	}

	/**
	 * 清除掉所有的選中狀态。
	 */

	private void clearSelection() {
		newsIv.setBackgroundResource(R.drawable.biz_navigation_tab_news);
		readIv.setBackgroundResource(R.drawable.biz_navigation_tab_read);
		topicIv.setBackgroundResource(R.drawable.biz_navigation_tab_topic);
		vaIv.setBackgroundResource(R.drawable.biz_navigation_tab_va);
		memberIv.setBackgroundResource(R.drawable.biz_navigation_tab_pc);

		newsTv.setTextColor(getResources().getColor(R.color.color_aaaaaa));
		readTv.setTextColor(getResources().getColor(R.color.color_aaaaaa));
		topicTv.setTextColor(getResources().getColor(R.color.color_aaaaaa));
		vaTv.setTextColor(getResources().getColor(R.color.color_aaaaaa));
		memberTv.setTextColor(getResources().getColor(R.color.color_aaaaaa));
	}

	/**
	 * 将所有的Fragment都置為隐藏狀态。
	 * 
	 * @param transaction
	 *            用于對Fragment執行操作的事務
	 */
	private void hideFragments(FragmentTransaction transaction) {
		if (newsFragment != null) {
			transaction.hide(newsFragment);
		}
		if (readFragment != null) {
			transaction.hide(readFragment);
		}
		if (topicFragment != null) {
			transaction.hide(topicFragment);
		}
		if (vaFragment != null) {
			transaction.hide(vaFragment);
		}
		if (memberFragment != null) {
			transaction.hide(memberFragment);
		}
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {

		if (keyCode == KeyEvent.KEYCODE_BACK) {
			if (tag.equals("1") || tag.equals("2") || tag.equals("3")|| tag.equals("4")) {
				setTabSelection(0);
			} else if (tag.equals("0")) {
				appExit();
			}
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}

	/**
	 * 退出app
	 */
	public void appExit() {
		if (!isAppExit) {
			isAppExit = true;
			Toast.makeText(this, "再按一次,退出應用", Toast.LENGTH_SHORT).show();
			handler.sendEmptyMessageDelayed(APPEXIT, 2000);
		} else {
			// 2s内再次按back時,isExit= true,執行以下操作,app退出
			System.exit(0);
		}
	}

	Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case APPEXIT:
				isAppExit = false;
				break;
			default:
				break;
			}
		};
	};
}
           

首先設定布局,接着綁定控件,設定監聽事件,當點選不同的控件時,調用setTabSelection()方法,在該方法中,

1.清除控件之前的狀态,clearSelection();

2.隐藏所有的 Fragment,hideFragments();

3.根據傳遞的index參數,進入到相應的case中,先改變目前控件的狀态,接着,判斷目前Fragment是否為null,當為null時,建立該Fragment,并将該Fragment加入到FragmentManager,管理起來,當不為null時,就直接顯示該Fragment,記得還要送出該事務,transaction.commit()。

    經過上面這幾步,就可以實作基本的功能了!我還實作了,onKeyDown()監聽事件(點選手機傳回鍵時的監聽),當點選傳回鍵時,如果目前顯示的不是主Fragment,那麼先跳轉到主Fragment,此時,再次點選傳回鍵時,便會看到提示“再按一次,退出應用”,若果是主Fragment,就如前面所說的。

    至此,經過上面的流程,我們就能大緻實作文章開頭時,展示的項目樣式,我們在實際開發中,隻需要更換圖檔等一些簡單的操作,就可以很快實作這樣的項目樣式!該項目樣式的實作,得益于很早之前看郭霖大牛的部落格,是以,在此感謝郭霖大牛!

   如果該文章你已經了解,那麼可以去看看這些文章,打造屬于你的萬能擴充卡和Android 滑動切換!

   如果你也需要實作這樣的項目架構樣式,那麼請下載下傳源碼吧!

ps:源碼下載下傳位址