商业级项目——基金client的架构设计与开发(上)
本项目是通力基金的商业级项目,声明:在此仅用于交流学习。该项目主要有三个主要功能模块:1、基金模块:包含基金的查询、展示等功能;2、账户模块:包含登录、充值、提现、收藏等功能;3、辅助模块:消息中心、帮助、意见反馈等。
项目执行首先会有一个闪屏页,然后进入的是一个新手引导页(仅仅显示一次),能够向右滑动,共4页图片,当滑到最后一张时,图片中会有一个进入的button,点击这个button进能够进入到App的主页。
主页中:以下是4个导航,依据用户点击的不同,会切换至不同的界面。
ok。我们如今開始来分享一下这个软件的实现过程。
新手引导页的话非常easy,非常多人都做过。总之就是使用一个viewPager来实现,使用一个pagerAdapter来填充viewpager的内容。假设直接继承pagerAdapter这个抽象类,须要重写getCount()、isViewFromObject()、destroyItem()、instantiateItem()等4个方法才干够为viewpager填充内容。我曾经的博客中具体介绍了新手引导页的开发。传送门:http://blog.csdn.net/sdksdk0/article/details/50043843 点击打开链接。所以这里就不再反复写了。
以下来分享一个这个主界面的设计,首先使用的是一个很经典的方法:TabHost。TabHost同意将多个控件放在同一个区域内。然后通过点击button来替换,这样就不用调用FragmentManager来进行替换的操作。
以下来看一下这个主界面的布局文件:
<?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">
<TabHost
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible">
<RelativeLayout
android:id="@+id/content_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_view">
<fragment
android:id="@+id/jijin_view"
android:name="com.zhilinghui.fund.fragment.JijinFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<fragment
android:id="@+id/member_view"
android:name="com.zhilinghui.fund.fragment.MemberFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:id="@+id/fs_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:name="com.zhilinghui.fund.fragment.FSFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<fragment
android:id="@+id/settings_view"
android:name="com.zhilinghui.fund.fragment.SettingsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<RelativeLayout
android:id="@+id/bottom_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/tab_bar_bg"
android:gravity="center_vertical">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/tab_selected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:background="@drawable/tab_scroll"
android:contentDescription="@null"
android:visibility="gone" />
<ImageView
android:id="@+id/notice_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="12dp"
android:layout_marginTop="10dp"
android:adjustViewBounds="true"
android:background="@drawable/notice_logo"
android:contentDescription="@null"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>
</TabHost>
<RelativeLayout
android:id="@+id/index_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/transparent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager_index"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.zhilinghui.fund.widget.PageControlView
android:id="@+id/pageControlView_index"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="30dp" />
</RelativeLayout>
在Activity中要找到这些button:
setContentView(R.layout.a_main); bottom_view = (RelativeLayout) findViewById(R.id.bottom_view); mTabHost = (TabHost) findViewById(android.R.id.tabhost); mTabs = (TabWidget) findViewById(android.R.id.tabs); mTabs.setDividerDrawable(null);从上面的布局文件里,我们能够看到,这个TabHost里面是加了图片和文字的。这样看起来会更加美观一点,加入图片的方法例如以下:
tab01 = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.item_tab_view, null); tab01.setBackgroundResource(R.drawable.tab_jijin_drawable); tab02 = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.item_tab_view, null); tab02.setBackgroundResource(R.drawable.tab_member_drawable); tab03 = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.item_tab_view, null); tab03.setBackgroundResource(R.drawable.tab_fs_drawable); tab04 = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.item_tab_view, null); tab04.setBackgroundResource(R.drawable.tab_settings_drawable); mTabHost.addTab(mTabHost.newTabSpec("0") .setIndicator(tab01) .setContent(R.id.jijin_view)); mTabHost.addTab(mTabHost.newTabSpec("1") .setIndicator(tab02) .setContent(R.id.member_view)); mTabHost.addTab(mTabHost.newTabSpec("2") .setIndicator(tab03) .setContent(R.id.fs_view)); mTabHost.addTab(mTabHost.newTabSpec("3") .setIndicator(tab04) .setContent(R.id.settings_view)); mTabHost.setCurrentTab(0); //设当前 Tab 为 0加入点击事件:
mTabHost.setOnTabChangedListener(mOnTabChangeListener);设置适配器:
// 导航栏适配器 adapter = new NavigatePagerAdapter(this, ids, mIndexOverListener, page_control); viewpager.setAdapter(adapter); viewpager.setOnPageChangeListener(mOnPageChangeListener);
(由于我虚拟机的分辨率没设置好。貌似图片有点失真了)
在第一页中上面那个能够滑动的自然也是一个viewpager了。以下就是一个listview第一个页面还具有下列刷新(包含上下箭头和时间)和载入很多其它的功能。
基金是有一个后台的,从server数据传输显示在这个轮播条上面。
以下的数据条目也是一样,由于这里没有过多的图片,所以不须要设置图片缓存(而某些项目的listview条目中有图片的话。我们就应该要考虑添加图片缓存功能了,从而避免太耗用户流量或内存溢出等问题)。
当我们点击这个基金进去的时候。比如第一个“活期通力宝",就会跳转到还有一个界面。这里具体的描写叙述了该基金的信息,比如基金经理、基金代码、收益率、同类排名等内容,然后还会加上一个折线图,从而更加清晰的描写叙述这个项目。给用户带来更好的体验。还有就是当数据与后台传输的时候,在这个界面还会有一个圆圈在转动,若网络无法连接,则会有一个我们自己定义好了的提示界面,说网络无法连接。
(在这里不提供公司的后台接口,所以这里的数据虚拟化了显示)。
@Override public void onRefresh() { mController.execute(new UIAsyncTask(getFavHandler, mDatabaseAdapter, BaseHandlerUI.REQUEST_GET_FAV)); } @Override public void onLoadMore() { onLoad(); } private void onLoad() { mListView.stopRefresh(); mListView.stopLoadMore(); }
@SuppressLint("SetJavaScriptEnabled") private void loadUrl() { showProgressDialog(context, context.getString(R.string.dlg_loading)); thread = new Thread(new Runnable() { @SuppressWarnings("deprecation") @Override public void run() { webview.getSettings().setJavaScriptEnabled(true); // webview.getSettings().setPluginsEnabled(true); webview.getSettings().setSupportZoom(true); webview.getSettings().setBuiltInZoomControls(true); //载入url前,设置图片堵塞 webview.getSettings().setBlockNetworkImage(true); webview.loadUrl(bean.url); MyWebViewClient myWebView = new MyWebViewClient(); webview.setWebViewClient(myWebView); } }); thread.start(); }
所有基金listview的适配:
@SuppressLint("ResourceAsColor") public class Text_Adapter extends BaseAdapter { List<FundTitleBean> items = new ArrayList<FundTitleBean>(); private LayoutInflater mInflater; private OnClickListener mOnClick; Context context; private boolean left = true; public Text_Adapter(Context context, List<FundTitleBean> items, OnClickListener mOnClick, boolean left) { super(); this.context = context; this.mInflater = LayoutInflater.from(context); this.items = items; this.mOnClick = mOnClick; this.left = left; } @Override public int getCount() { return items.size(); } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; // ViewHolder 是内部类, 仅仅有一个成员(name) TextView if (convertView == null) { holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.item_list_txt_view, null); holder.name = (TextView) convertView .findViewById(R.id.name); // 这里的 name 是一个 TextView convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); //getTag 返回: 一个 Object 引用 } holder.name.setOnClickListener(mOnClick); holder.name.setTag(position); holder.name.setText(items.get(position).name); if (items.get(position).isSelected) { if (left) { convertView.setBackgroundResource(R.drawable.choose_s_left); } else { convertView.setBackgroundResource(R.drawable.choose_s_right); } } else { convertView.setBackgroundResource(R.drawable.choose_list_selector); } return convertView; } private class ViewHolder { TextView name; } }无网络时的错误提示Activity代码:
public void initView() { title = (TextView) findViewById(R.id.title_txt); title.setText(getString(R.string.dlg_net_err)); left_btn = (TextView) findViewById(R.id.left_btn); left_btn.setVisibility(View.VISIBLE); left_btn.setOnClickListener(this); left_btn.setVisibility(View.VISIBLE); right_btn = (TextView) findViewById(R.id.right_btn); right_btn.setVisibility(View.GONE); }
讲到这里,还须要分享一个知识就是关于Application的使用:在非常多大型项目中都会有
Application和Actovotu,Service一样是android框架的一个系统组件,当android程序启动时系统会创建一个 application对象,用来 * 存储系统的一些信息。通常我们是不须要指定一个Application的,这时系统会自己主动帮我们创建。假设须要创建自己 的Application,也非常简 * 单创建一个类继承 Application并在manifest的application标签中进行注冊(仅仅须要给Application标签添加个name属性把自己 * 的 Application的名字定入就可以)。 * android系统会为每一个程序执行时创建一个Application类的对象且仅创建一个,所以Application能够说是单例 (singleton)模式的一个类.且 * application对象的生命周期是整个程序中最长的。它的生命周期就等于这个程序的生命周期。由于它是全局 的单例的,所以在不同的Activity,Service中 * 获得的对象都是同一个对象。
所以通过Application来进行一些,数据传递,数据共享 等,数据缓存等操作。 * <p/> * 二.程序的入口 * Android使用Google Dalvik VM,相对于传统Java VM而言有着非常大的不同,在Sun的Java体系中入口点和标准c语言一样是main(), * 而每一个Android程序都包括着一个Application实例。一个Application实例中有多个Activity、 Service、ContentProvider或 * Broadcast Receiver。 * 事实上在android.app.Application这个包的onCreate才是真正的Android入口点,仅仅只是大多数开发人员无需重写该类。 * <p/> * 第一步、写一个全局的单例模式的MyApplication继承自Application 重写onCreate * 第二步、配置全局的Context *
<application android:name="com.zhilinghui.fund.app.GFFApp"></application>
ok。今天主要是分享了一下这个商业级基金项目的导航设置和第一个界面(主界面)的设计与功能介绍。下一次将分享”个人中心“、”交易界面"、“帮助中心”的设计与实现。当然,在下一篇博客中我会贴出这个项目的源代码哦。今天的就暂不提供源代码。欢迎关注!
记住:下一次博客会贴出整个项目的源代码。可免费下载使用!
欢迎关注。