iOS转android之基础架构

一、前言

随着混合开发、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,那是后话。





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

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

  1. 头部使用一个透明的view填充StatusBar
  2. 中间view作为NavigationBar来使用,可以添加左右按钮和中间标题
  3. 底部还可以插入一个宽度为1的View作为NavigationBar底部分割线

    









    
    

    
    

代码中看到总体高度设置为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的一部分放到整个页面的底部,高度可以直接确定,逻辑简单了不少


    

        
        

        

    

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

五、内容区域

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


    

在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





    
    


在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 mListFragmentEntity = new ArrayList();
        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之基础架构)