美文网首页Android 开发
iOS转android之基础架构

iOS转android之基础架构

作者: 移动端_小刚哥 | 来源:发表于2019-01-07 11:33 被阅读91次

    一、前言

    随着混合开发、android快应用热更新、以及微信的小程序开发的发展,虽然苹果官方极力限制iOS开发中使用混合开发和热更新,但是隐隐感觉iOS原生开发的重要性在下降,像诺基亚一样短时间内被新技术迅速击垮也不是不可能的。对比iOS先简单介绍一下android中的一些关键词

    • Activity类似Controller
    • Fragment类似UIView
    • Dao类似Model

    暂时可以这么认为,但是要知道差别还是挺大的,例如Fragment比iOS中UIView强大的多,有自己的生命周期方法,说其相当于Controller也不过分,但是现在我们不深究,为了降低入门的学习成本。Android中有MVC,但是好像比较落后了,MVP使用比较多,这里也暂时不谈论,我们还是参照iOS使用MVC,Activity相当于C,Fragment相当于V,Dao相当于M,先入门写出来一个完整app,其余的以后优化。Android有一些特点和iOS是有区别的,例如Android不一定有返回按钮因为Android手机有实体返回按键,例如Android的标题可能不在头部中间而是紧挨着返回键,为了降低学习成本这里我们都按照iOS风格来开发。

    二、整体思路

    在iOS中Controller有一个父类,称之为BaseController,同样android中也有这个父类,称之为BaseActivity,那么在这个父类中要实现那些功能呢?分为三大部分:

    • 头部的NavigationBar要可以实现自身的显示和隐藏,创建和隐藏左侧返回按钮,创建和隐藏右侧按钮,添加中间部分的标题,将背景延伸到屏幕顶部Statusbar实现NavigationBar和StatusBar融为一体的效果,现在很多手机都是不规则的屏幕,如果不融为一体那么头部会出现很宽的状态栏,不协调。
    • 中间的内容显示区域最重要的是要能实现隐藏底部的Tabbar和头部的NavigationBar时内容要能跟着向上和向下延伸。
    • 底部的Tabbar能创建多个按钮以及实现点击不同按钮切换到不同的功能模块,可以实现显示角标的功能,配合推送使用

    我的整体实现是新建BaseActivity类布局文件使用RelativeLayout,Android中有很多中布局为什么我选择使用RelativeLayout呢??,很简单,因为其他的我不会啊😂,Android中有至少6中布局,想要不实际开发功能而掌握这些布局是很难的,所以我使用我比较熟悉的RelativeLayout,没准随着我的深入理解我会改用其他的layout,那是后话。

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffff"
        tools:context=".base.activity.BaseActivity"
        android:id="@+id/main_root_layout"
        >
    
    </RelativeLayout>
    

    三、屏幕头部NavigationBar和StatusBar的实现

    上面我们确定了整体布局使用RelativeLayout下面我们往这个父类中添加头部NavigationBar和StatusBar,要实现NavigationBar和StatusBar融为一体效果那么背景使用同一个view

    1. 头部使用一个透明的view填充StatusBar
    2. 中间view作为NavigationBar来使用,可以添加左右按钮和中间标题
    3. 底部还可以插入一个宽度为1的View作为NavigationBar底部分割线
    <?xml version="1.0" encoding="utf-8"?>
        <!--
            具体layout_height在java类中获取statusbar高度之后进行设置
            layout_height的值为navigationbar告诉加上statusBar高度
        -->
    <RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/navigationBarBackView"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:background="@mipmap/nav_back"
        >
    
    
    <!--填充状态栏背景部分 默认和navigationbar连为一体 所以设置为透明色-->
    <View
        android:id="@+id/navigationBarTopClearView"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:background="#00000000"
        />
    
    
    <RelativeLayout
        android:id="@+id/navigationBar"
        android:layout_width="match_parent"
        android:layout_height="58dp"
        android:layout_below="@+id/navigationBarTopClearView"
        android:layout_above="@+id/nav_bottom_line"
        android:background="#00000000"
        >
    
        <!--标题-->
        <TextView
            android:id="@+id/nav_text_title"
            android:text="标题"
            android:textSize="18dp"
            android:textColor="#fff"
            android:gravity="center"
            android:singleLine="true"
            android:ellipsize="marquee"
            android:layout_width="100dp"
            android:layout_centerInParent="true"
            android:layout_height="wrap_content" />
    
        <!--返回按钮-->
        <Button
            android:id="@+id/button_backward"
            android:layout_width="70dp"
            android:layout_height="match_parent"
            android:drawableLeft="@mipmap/tm_nav_back"
            android:drawablePadding="6dp"
            android:layout_marginLeft="15dp"
            android:background="#00000000"
            android:ellipsize="end"
            android:gravity="center"
            android:onClick="onClick"
            android:paddingLeft="5dp"
            android:singleLine="true"
            android:text=""
            android:textColor="#ffffff"
            android:textSize="15dp"
            android:visibility="invisible" />
    
        <!--右侧按钮-->
        <Button
            android:id="@+id/button_forward"
            android:layout_width="70dp"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
            android:drawablePadding="6dp"
            android:background="#00000000"
            android:ellipsize="end"
            android:gravity="center"
            android:onClick="onClick"
            android:paddingLeft="5dp"
            android:singleLine="true"
            android:text="搜索"
            android:textColor="#ffffffff"
            android:textSize="15dp"
            android:visibility="invisible" />
    </RelativeLayout>
    
    <!--导航栏底部分割线-->
    <View
        android:id="@+id/nav_bottom_line"
        android:layout_height="1px"
        android:layout_width="match_parent"
        android:layout_alignParentBottom="true"
        android:background="#C7C7C7"/>
    
    </RelativeLayout>
    

    代码中看到总体高度设置为0,这是因为Android手机种类繁多,StatusBar高度不确定,所以在布局文件中不能确定StatusBar的具体高度,需要在java类中来更新高度值,背景view的高度为获取的StatusBar高度加上NavigationBar的高度。

    //整个navigationBar和statusBar的背景视图,实现navigationBar和statusbar连为一体的效果
            navBackViewLayout = (RelativeLayout)findViewById(R.id.navigationBarBackView);
            //填充statusbar背景的view 设置为透明色
            statusBarBackView = (View)findViewById(R.id.navigationBarTopClearView);
            //navigationBar的背景布局
            navLayout = (RelativeLayout)findViewById(R.id.navigationBar);
            //navigationBar中间的标题
            titleTextView = (TextView)findViewById(R.id.nav_text_title); //标题
            //navigationbar左侧按钮 (返回按钮,可设置图片和文字)
            leftBtn = (Button)findViewById(R.id.button_backward);//返回按钮
            //navigationBar右侧按钮
            rightBtn = (Button)findViewById(R.id.button_forward);//右侧按钮
            //导航栏分割线
            navSepLine = (View)findViewById(R.id.nav_bottom_line);
    
    
        @Override
        public void onClick( View v ) {
            if (v.getId()==R.id.button_backward){//返回按钮
                leftBtnDidClicked(v);
            }else if (v.getId()==R.id.button_forward){//右侧按钮
                rightBtnDidClicked(v);
            }
        }
    
    
        /**
         * 点击左侧按钮的响应方法,在子类中做具体操作
         * @param view
         */
        public void leftBtnDidClicked(View view){
    
        }
    
        /**
         * 点击右侧按钮的响应方法 在子类中做具体操作
         * @param view
         */
        public void rightBtnDidClicked(View view){
    
        }
    
    
        /**
         * 显示navigationbar上的title信息
         * @param title
         */
        public void createTitle(String title){
            this.titleTextView.setText(title);
        }
    
    
        /**
         * 显示返回按钮
         */
        public void createBackBtn(){
            leftBtn.setVisibility(View.VISIBLE);
        }
    
    
        /**
         * 设置显示/隐藏navigationbar
         * @param isShow true显示 false隐藏
         */
        public void isShowNavigationBar( boolean isShow ){
            if (navBackViewLayout!=null){
                if (isShow){ //显示navigationbar
                    navBackViewLayout.setVisibility(View.VISIBLE);
                }else {//隐藏navigationbar
                    navBackViewLayout.setVisibility(View.GONE);
                }
            }
        }
    

    根据实际设备动态修改statusbar背景填充区域高度,使得navigationbar能正确显示

    /**
         * 根据实际情况适配navigationBar
         */
        private void initStatusBar(){
            //让布局扩展到statusbar后面
            View decorView  = getWindow().getDecorView();
            decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
    
    
         
            Class c = null;
            int statusBarHeight = 0;
            try {
                c = Class.forName("com.android.internal.R$dimen");
                Object obj = c.newInstance();
                Field field = c.getField("status_bar_height");
                int x = Integer.parseInt(field.get(obj).toString());
                statusBarHeight = this.getResources().getDimensionPixelSize(x);
                Log.d("状态栏绝对高度为(单位px)", String.valueOf(statusBarHeight));
    
            } catch (Exception e) {
                e.printStackTrace();
                statusBarHeight = 20;
            }
    
            //设置状态栏背景填充高度
            ViewGroup.LayoutParams layoutParams = statusBarBackView.getLayoutParams();
            layoutParams.height = statusBarHeight;
            statusBarBackView.setLayoutParams(layoutParams);
    
            ViewGroup.LayoutParams navLayoutPara = navBackViewLayout.getLayoutParams();
            navLayoutPara.height = navLayout.getLayoutParams().height + statusBarHeight + navSepLine.getLayoutParams().height;
            navBackViewLayout.setLayoutParams(navLayoutPara);
        }
    
    

    四、Tabbar的实现

    和NavigationBar类似,作为BaseActivity的一部分放到整个页面的底部,高度可以直接确定,逻辑简单了不少

    <!--tabbar布局-->
        <RelativeLayout
            android:id="@+id/bottomBarLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
        >
    
            <!--tabbar上边的分割线-->
            <View
            android:id="@+id/bottomTopLineView"
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:background="#C7C7C7"
            />
    
            <com.example.jizhigang.crm_android_j.base.widge.BottomBar
            android:id="@+id/bottomBar"
            android:layout_below="@+id/bottomTopLineView"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:background="#ffffffff"
            android:layout_gravity="bottom"
            />
    
        </RelativeLayout>
    

    在java类中使用配合下面👇的内容一块看,因为BottomBar和中间显示区域有联动

    五、内容区域

    中间内容显示区域使用Fragment来实现,要在java代码中动态添加Fragment,那么布局文件应该使用FrameLayout

    <!--android:layout_alignParentBottom="true"-->
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/fragment_container"
            android:layout_below="@+id/navigationBarBackView"
            android:layout_above="@+id/bottomBarLayout"
            android:layout_alignWithParentIfMissing="true"
            android:background="#EFF3F6"
            />
    

    在BaseActivity类中使用

    /**
         * 给中间内容显示区域赋值
         * @param fragment
         */
        public void setContentFragment( Fragment fragment ){
            if (fragment != null){
                getSupportFragmentManager()
                        .beginTransaction()
                        .add(R.id.fragment_container,fragment)
                        .commit();
            }
        }
    

    首页要实现点击tabbar按钮切换功能模块,新建一个Fragment添加一个左右滚动控件CustomerViewPager,继承自ViewPager类,ViewPager无法实现关闭左右滑动切换功能模块的功能,这里使用子类,具体代码见demo

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".base.fragment.TabbarFragment">
    
    
        <com.example.jizhigang.crm_android_j.base.widge.CustomerViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            >
        </com.example.jizhigang.crm_android_j.base.widge.CustomerViewPager>
    
    </FrameLayout>
    

    在Fragment的java类中使用

    @Override
        public View onCreateView( LayoutInflater inflater, ViewGroup container,
                                  Bundle savedInstanceState ) {
    
            contentView = inflater.inflate(R.layout.fragment_tabbar, container, false);
            //viewPager
            viewPager = (CustomerViewPager)contentView.findViewById(R.id.viewPager);
    
            bottomBarTab1 = new BottomBarTab(getContext(),R.mipmap.customer_unselected,R.mipmap.customer,"宝贝");
            bottomBarTab2 = new BottomBarTab(getContext(),R.mipmap.message,R.mipmap.message_selected,"消息");
            bottomBarTab3 = new BottomBarTab(getContext(),R.mipmap.mine,R.mipmap.mine_selected,"我的");
    
            CustomerFragment customerFragment = new CustomerFragment();
            MessageFragment messageFragment = new MessageFragment();
            MineFragment mineFragment = new MineFragment();
    
            List<FragmentEntity> mListFragmentEntity = new ArrayList<FragmentEntity>();
            mListFragmentEntity.add(getFragmentEntity(customerFragment,"CustomerFragment"));
            mListFragmentEntity.add(getFragmentEntity(messageFragment,"MessageFragment"));
            mListFragmentEntity.add(getFragmentEntity(mineFragment,"MineFragment"));
    
            viewPager.setAdapter(new MyFragmentAdapter((TabbarActivity)getContext(),mListFragmentEntity));
            viewPager.setCurrentItem(0);
            viewPager.setCanScroll(false); //不要左右滚动
            viewPager.setOffscreenPageLimit(3);
            viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled( int i, float v, int i1 ) {
    
                }
    
                @Override
                public void onPageSelected( int i ) {
                    for (int j = 0; j < ((TabbarActivity) getContext()).getBottomBar().getBottomBarTabs().size(); j++){
                        ((TabbarActivity) getContext()).getBottomBar().getBottomBarTabs().get(j).setSelected(false);
                    }
                    ((TabbarActivity) getContext()).getBottomBar().getBottomBarTabs().get(i).setSelected(true);
                }
    
                @Override
                public void onPageScrollStateChanged( int i ) {
    
                }
    
            });
    
    
    
    
    
    
    
            ((TabbarActivity) getContext()).getBottomBar().addItem(bottomBarTab1).addItem(bottomBarTab2).addItem(bottomBarTab3);
            ((TabbarActivity) getContext()).getBottomBar().setOnTabSelectedListener(new BottomBar.OnTabSelectedListener() {
                /**
                 * 点击tab时调用(点击的和之前选中的不是同一个时执行)
                 * @param position 当前选中的索引
                 * @param prePosition 被取消的索引
                 */
                @Override
                public void onTabSelected( int position, int prePosition ) {
                    Log.d("onTabSelected","position="+position+"prePosition="+prePosition);
                    viewPager.setCurrentItem(position);
                    switch (position){
                        case 0:
                            ((TabbarActivity) getContext()).createTitle("客户");
                            ((TabbarActivity) getContext()).isShowNavigationBar(true);
                            break;
                        case 1:
                            ((TabbarActivity) getContext()).createTitle("消息");
                            ((TabbarActivity) getContext()).isShowNavigationBar(true);
                            break;
                        case 2:
                            ((TabbarActivity) getContext()).createTitle("我的");
                            ((TabbarActivity) getContext()).isShowNavigationBar(true);
                            break;
                    }
                }
    
    
                /**
                 * tab取消选中(点击的和之前选中的不是同一个时执行)
                 * @param position 取消选中tab的索引值
                 */
                @Override
                public void onTabUnselected( int position ) {
                    Log.d("onTabUnselected","position="+position);
                }
    
                /**
                 * 两次点击同一个tab时调用
                 * @param position 点击tab的索引
                 */
                @Override
                public void onTabReselected( int position ) {
                    Log.d("onTabReselected","position="+position);
                }
            });
    
            //设置默认选中的值
            ((TabbarActivity) getContext()).getBottomBar().getBottomBarTabs().get(0).setSelected(true);
    
            // Inflate the layout for this fragment
            return contentView;
        }
    

    到这里BaseActivity新建完成,需要注意的是

    android:layout_alignWithParentIfMissing="true"
    

    当所以来的控件为空时那么以父试图为准,设置其所依赖的视图

    android:visibility="gone"
    

    可以实现隐藏和显示NavigationBar和Tabbar功能

    demo地址
    https://github.com/jzglovewjr/crmandroidj

    相关文章

      网友评论

        本文标题:iOS转android之基础架构

        本文链接:https://www.haomeiwen.com/subject/hhgyrqtx.html