Android开发之麦田福音网移动版本演示程序

原文来自 http://caotian.appspot.com/2011/02/18/mtfy-android-demo.html  感谢作者的分享!

         Android手机终于入手了,HTC Desire G7 水货2700的价格也不算太贵,终于可以开始我的Android开发之旅了,没有真机只有模拟器我还真有点底气不足。

         近来给麦田福音网规划移动平台,制作了一个麦田福音网部分功能的移动程序。演示程序只做展示,不提供登陆交互,因此还是比较简单的,打算做一个类似浏览器的外壳,提供几个按钮可以切换不同的功能,再做一个导航工具栏就可以了。当然,这之前先把3G版本的网页做出来,添加了一个m.php,使用mod参数控制调用不同的功能,这个不在本文讨论范围内。

         程序功能十分简单,只有一个名为MainPage的Activity。常规的,先把布局整理出来,老老实实地用Tab控件拖了四个,分别对应“麦田沙龙”,“麦田微博”,“麦田杂志”,“公共主页”,然后在每个Tab里嵌入一个WebView控件,充当浏览器功能,然后分别针对每个tab增加click事件响应函数,设定对应的WebView对加载指定的功能所需要的网页。写完后,发现这样挺傻的,WebView维护了四个,要是再添加Tab还要再增加WebView,虽然对Android刚刚入门,依然觉得不同的Tab应该可以共享一个WebView。而且Tab最好可以动态生成,这样可以在代码中控制Tab的生成,比写死到界面xml文件中要好的多。于是,打开main.xml,修改页面布局为:

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/TabHost01" android:layout_width="fill_parent"  
    android:layout_height="fill_parent">  
    <LinearLayout android:layout_width="fill_parent"  
        android:orientation="vertical" android:layout_height="fill_parent">  
        <TabWidget android:id="@android:id/tabs"  
            android:layout_width="fill_parent"  
            android:layout_height="wrap_content" />  
        <FrameLayout android:id="@android:id/tabcontent"  
            android:layout_width="fill_parent"  
            android:layout_height="fill_parent">         
        </FrameLayout>  
    </LinearLayout>  
    
    <LinearLayout android:orientation="horizontal"
		android:id="@+id/btnbar" android:background="#333333"
		android:layout_width="fill_parent" android:layout_gravity="bottom"
		android:layout_height="40dp">
		<RelativeLayout android:layout_width="50dp" android:layout_height="fill_parent"
			android:layout_marginLeft="10dp">
			<ImageView android:src="@drawable/left" android:layout_centerInParent="true"
				android:layout_width="wrap_content" android:layout_height="wrap_content" 
				android:id="@+id/btnleft"
				/>
		</RelativeLayout>
		<RelativeLayout android:layout_width="50dp" android:layout_height="fill_parent"
			android:layout_marginLeft="10dp">
			<ImageView android:src="@drawable/right" android:layout_centerInParent="true"
				android:layout_width="wrap_content" android:layout_height="wrap_content" 
				android:id="@+id/btnright"
				/>
		</RelativeLayout>
		<RelativeLayout android:layout_width="50dp" android:layout_height="fill_parent"
			android:layout_marginLeft="10dp">
			<ImageView android:src="@drawable/home" android:layout_centerInParent="true"
				android:layout_width="wrap_content" android:layout_height="wrap_content" 
				android:id="@+id/btnhome"
				/>
		</RelativeLayout>		
		<RelativeLayout android:layout_width="50dp" android:layout_height="fill_parent"
			android:layout_marginLeft="10dp">
			<ImageView android:src="@drawable/refresh" android:layout_centerInParent="true"
				android:layout_width="wrap_content" android:layout_height="wrap_content" 
				android:id="@+id/btnrefresh"
				/>
		</RelativeLayout>	
		<RelativeLayout android:layout_width="50dp" android:layout_height="fill_parent"
			android:layout_marginLeft="10dp">
			<ImageView android:src="@drawable/quit" android:layout_centerInParent="true"
				android:layout_width="wrap_content" android:layout_height="wrap_content" 
				android:id="@+id/btnquit"
				/>
		</RelativeLayout>					
	</LinearLayout>
</TabHost>  

          正文是一排导航按钮图片,没有什么好说的。为简单,此处一个一个写出来,没有动态生成,也没必要。同时准备好导航图片,放到res\drawable-mdpi下。

 

          下面简单说说演示程序的几点需要编程的地方:

1)       Tab的动态生成:这个毫无疑问,使用工厂生成就是了。新建一个TabFactory类,继承自abContentFactory。Tab中应包含WebView,由于共享WebView,所以WebView采用单例模式,静态只生成一次就好了,并且给它指定一个固定的数字ID,我使用了100,以方便其它页面取得对WebView的引用。代码如下:

package org.mtfy;

import android.content.Context;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.TabHost.TabContentFactory;

public class TabFactory implements TabContentFactory {
	private Context con;
	private static WebView webView;
	static final int webview = 0x100;
	public TabFactory(Context c){
		con = c;
	}
			
	public View createTabContent(String tag) {
		if(webView==null)
		{
			webView = new WebView(con);
			webView.setId(webview);
			WebSettings webSettings = webView.getSettings();   
			webSettings.setJavaScriptEnabled(true);
			//webSettings.setBuiltInZoomControls(true);
			webView.setWebViewClient(new WebViewClient(){

				@Override
				public boolean shouldOverrideUrlLoading(WebView view, String url) {
					view.loadUrl(url);
					return true;
				}
				
			});
		}
		return webView;
	}

}

2)       在MainPage的Activity中,定义一些常量和变量。TabHost变量用来控制生成的Tab添加到当前Activity 中。webView用来引用唯一的WebView。几个ImageView为导航图片按钮的引用, url1-4为四个Tab页面对应的主url。

	private TabHost tabHost;
	private WebView webView;
	private ImageView imageViewLeft;
	private ImageView imageViewRight;
	private ImageView imageViewHome;
	private ImageView imageViewRefresh;
	private ImageView imageViewQuit;
	static final int webview = 0x100;
	static final String url1 = "http://www.mtfy.org/m.php?mod=home";
	static final String url2 = "http://www.mtfy.org/m.php?mod=t";
	static final String url3 = "http://www.mtfy.org/m.php?mod=magazine";
	static final String url4 = "http://www.mtfy.org/m.php?mod=public";

3)       OnCreate函数中,增加Tab动态创建的代码,并设置第一个Tab为选中状态:

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		try {
			tabHost = (TabHost) this.findViewById(R.id.TabHost01);
			tabHost.setup();

			tabHost.addTab(tabHost.newTabSpec("tab1")
					.setContent(new TabFactory(this)).setIndicator("麦田沙龙"));
			tabHost.addTab(tabHost.newTabSpec("tab2")
					.setContent(new TabFactory(this)).setIndicator("麦田微博"));
			tabHost.addTab(tabHost.newTabSpec("tab3")
					.setContent(new TabFactory(this)).setIndicator("麦田杂志"));
			tabHost.addTab(tabHost.newTabSpec("tab4")
					.setContent(new TabFactory(this)).setIndicator("公共主页"));
			tabHost.setCurrentTab(0);
			final TabWidget tabWidget = tabHost.getTabWidget();
			for (int i = 0; i < tabWidget.getChildCount(); i++) {
				tabWidget.getChildAt(i).getLayoutParams().height = 40;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		webView = (WebView) this.findViewById(webview);
		webView.loadUrl(url1);
		OnTabChangeListener changeList = new OnTabChangeListener() {

			public void onTabChanged(String tabId) {
				if (tabId.equals("tab1")) {
					webView.loadUrl(url1);
				} else if (tabId.equals("tab2")) {
					webView.loadUrl(url2);
				} else if (tabId.equals("tab3")) {
					webView.loadUrl(url3);
				} else if (tabId.equals("tab4")) {
					webView.loadUrl(url4);
				}
				webView.clearHistory();
			}

		};
		tabHost.setOnTabChangedListener(changeList);
		imageViewLeft = (ImageView) this.findViewById(R.id.btnleft);
		imageViewLeft.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				webView.goBack();
			}
		});

		imageViewRight = (ImageView) this.findViewById(R.id.btnright);
		imageViewRight.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				webView.goForward();
			}
		});

		imageViewHome = (ImageView) this.findViewById(R.id.btnhome);
		imageViewHome.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				int currId = tabHost.getCurrentTab();
				switch (currId) {
				case 0:
					webView.loadUrl(url1);
					break;
				case 1:
					webView.loadUrl(url2);
					break;
				case 2:
					webView.loadUrl(url3);
					break;
				case 3:
					webView.loadUrl(url4);
					break;
				}
			}
		});

		imageViewRefresh = (ImageView) this.findViewById(R.id.btnrefresh);
		imageViewRefresh.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				webView.reload();
			}
		});

		imageViewQuit = (ImageView) this.findViewById(R.id.btnquit);
		imageViewQuit.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				quitConfirm();
			}

		});
	}

4)       取得WebView的引用,并默认加载第一个地址,即第一个Tab对应的网址。

webView = (WebView) this.findViewById(webview); 
webView.loadUrl(url1);

5)       增加Tab的TabChangeListener事件,用来响应各个Tab的点击。由于几个不同的Tab共享同一个WebView,因此切换Tab的时候,同时清除WebView的缓存,防止点击后退的时候,后退到非当前Tab下的页面。

OnTabChangeListener changeList = new OnTabChangeListener() {

			public void onTabChanged(String tabId) {
				if (tabId.equals("tab1")) {
					webView.loadUrl(url1);
				} else if (tabId.equals("tab2")) {
					webView.loadUrl(url2);
				} else if (tabId.equals("tab3")) {
					webView.loadUrl(url3);
				} else if (tabId.equals("tab4")) {
					webView.loadUrl(url4);
				}
				webView.clearHistory();
			}

		};
		tabHost.setOnTabChangedListener(changeList);

6)       增加几个导航图片按钮的点击事件,分别用来后退,前进,主页,刷新,退出。点击主页的时候,先取得当前Tab,再判断需要加载哪个url。退出按钮调用了退出确认函数quitConfirm,用来询问用户是否要调用,函数内容比较简单,只是显示一个对话框,用户点确认就退出系统,否则不做处理返回。

imageViewLeft = (ImageView) this.findViewById(R.id.btnleft);
		imageViewLeft.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				webView.goBack();
			}
		});

		imageViewRight = (ImageView) this.findViewById(R.id.btnright);
		imageViewRight.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				webView.goForward();
			}
		});

		imageViewHome = (ImageView) this.findViewById(R.id.btnhome);
		imageViewHome.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				int currId = tabHost.getCurrentTab();
				switch (currId) {
				case 0:
					webView.loadUrl(url1);
					break;
				case 1:
					webView.loadUrl(url2);
					break;
				case 2:
					webView.loadUrl(url3);
					break;
				case 3:
					webView.loadUrl(url4);
					break;
				}
			}
		});

		imageViewRefresh = (ImageView) this.findViewById(R.id.btnrefresh);
		imageViewRefresh.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				webView.reload();
			}
		});

		imageViewQuit = (ImageView) this.findViewById(R.id.btnquit);
		imageViewQuit.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				quitConfirm();
			}

		});

protected void quitConfirm() {
		AlertDialog.Builder builder = new Builder(MainPage.this);
		builder.setMessage("确定要退出麦田福音吗?");
		builder.setTitle("麦田福音提示");
		builder.setPositiveButton("确认",
				new android.content.DialogInterface.OnClickListener() {

					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
						System.exit(0);
					}
				});
		builder.setNegativeButton("取消",
				new android.content.DialogInterface.OnClickListener() {

					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				});
		builder.create().show();
	}


7)       由于手机上的返回键,默认会直接关闭Activity,因为还要检测返回键,如果按下了,再判断WebView是否有历史记录,如果有就后退,没有就提示是否退出系统,我见主流的软件都是这样做,我也不多想,仿冒一个就是了。

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
			if (webView.canGoBack()) {
				webView.goBack();
			} else {
				quitConfirm();
			}
			return false;
		}
		return false;
	}

至此,程序完毕,在仿真器中打开看一下 ,效果还不错:

打包成apk文件,部署到手机中:

该演示程序比较简单,本文只流水记录一下开发步骤,至此Android开发大体有了点点的了解。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值