Android 开发

iOS转android之基础架构

2019-01-07  本文已影响91人  移动端_小刚哥

一、前言

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

暂时可以这么认为,但是要知道差别还是挺大的,例如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,那么在这个父类中要实现那些功能呢?分为三大部分:

我的整体实现是新建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

上一篇 下一篇

猜你喜欢

热点阅读