项目需求讨论-HyBrid模式需求改造

公司有个项目,是需要有呈现大量的图表及统计的饼状图,因为考虑到要有ios,Android及web端。所以为了统一就ios和Android都是做一个外壳,也就是打开原生的APP,但是其实里面就是个webview,直接浏览固定网址,然后所有的登录,查看等操作就是直接在网页上面操作,这样需求改了图表等,就可以直接web前段做完,我们Android和ios就都更新好了。但是这样就带来一个问题,比如在手机上浏览这个网页,像一些下拉框,点击按钮,横向滑动菜单等,操作起来很不方便。体验效果很差。但是不可能说全部把这个项目推到重来,于是我们决定中间的部分还是用网页的形式,而那些菜单,比如下拉框,横向菜单等都用原生来做。然后当点击原生的菜单,来与web端进行交互,来使网页刷新。

好,我们现在看到了,上面的菜单我们需要的东西是左上角一个返回按钮,二个下拉框,一个横向的滚动菜单(图片里面只显示了五个,其实有9个,可以横向滚动)。

下面菜单其实就是三个按钮,或者设置成底部tab菜单也可以。


本文重点就说讲解上面的菜单实现,及如果与网页来进行交互。

第一:原生处的菜单实现

Spinner(下拉选择框)

Spinner选择框的基本使用方式,我这边不会多提,比较一般开发的人都会。
比如:Spinner下拉框功能使用

这里我提二个大家可能会额外遇到的情况:
在写完spinner的每个选项的点击事件后。

spinner.setOnItemSelectedListener(newAdapterView.OnItemSelectedListener() {
      @Override
      public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            //这个方法里可以对点击事件进行处理
            //i指的是点击的位置,通过i可以取到相应的数据源
}
      @Override
      public void onNothingSelected(AdapterView<?> adapterView) {
}
});

然后你就开心的跑起了你的代码,发现我们刚进去界面,onItemSelected就被调用了一次。 what the fuck,我都还没有进行点击选项,怎么就被调用了。因为Spinner默认显示第一项内容,等于就是选中了第一项,也就会执行一遍onItemSelected方法。

解决方法:在调用setOnItemSelectedListener方法前,调用spinner.setSelection(0, false);默认不选中第一个,就OK了。

2.Spinner下拉框中的布局,也就是我点了Spinner后,出现的让你选择的界面的每个item的样式很简单,也就是Spinner.setAdapter中的adapter的布局设置为我们自己的布局就可以了。好。我们又开心的跑动起了代码,我们那个时间选择框选了2015年,但是我们发现。我们的 Spinner选中后的字体颜色可能是黑色,但是我们的背景也是黑色。WHF,所以我们要把选中的字体颜色也要换成白色。

我们就要设置我们选好后的字体的颜色值,或者是字体大小怎么办。

解决方法:这个选好后显示结果的其实是个TextView。而且刚上面设置spinner点击事件的监听的方法
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l)中的这个view就是我们选中的view.所以我们只需要((TextView) view).setTextColor(getResources().getColor(android.R.color.white));同理设置大小等就都能处理。

TabLayout (横向选择菜单)

同样基本的操作使用大家应该还是都会。比如说Material Design 之 TabLayout 使用

同样也会提到一个比较好的需求:
需求1:比如菜单只有3个,那我们肯定是希望在一个屏幕中就能显示,并且是平分的方式,呈现:

需求2:比如恰好菜单有8个之多,我们肯定就希望是滚动的,不是挤在一个屏幕:

大家都知道,让TabLayout实现需求1和需求2,我们只要设置TabLayout的Mode分比为:TabLayout.MODE_FIXEDTabLayout.MODE_SCROLLABLE

那我们就想到了。我们在TabLayout把菜单Tab都加入后。我们把这些Tab的宽度的总和算出来。再和整个屏幕的宽度进行比较,如果比屏幕宽度小,就设为TabLayout.MODE_FIXED,如果比手机屏幕宽度大就设为TabLayout.MODE_SCROLLABLE

public class TabLayoutUtil {

    public static void dynamicSetTabLayoutMode(TabLayout tabLayout) {
        int tabWidth = calculateTabWidth(tabLayout);
        int screenWidth = getScreenWidth();

        if (tabWidth <= screenWidth) {
            tabLayout.setTabMode(TabLayout.MODE_FIXED);
        } else {
            tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
        }
    }

    private static int calculateTabWidth(TabLayout tabLayout) {
        int tabWidth = 0;
        for (int i = 0; i < tabLayout.getChildCount(); i++) {
            final View view = tabLayout.getChildAt(i);
            view.measure(0,0); //通知父 View 测量,以便于能够保证获取到宽高
            tabWidth += view.getMeasuredWidth();
        }
        return tabWidth;
    }

    public static int getScreenWidth() {
        return LockWebAppliction.getInstance().getResources().getDisplayMetrics().widthPixels;
    }
}
public class LockWebAppliction extends Application {
    private static Context context;

    public static Context getInstance(){
        return context;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        this.context = this;
        
    }
}

所以我们接下去有了这个工具类,只需要:

        TabLayout tablayout = (TabLayout) findViewById(R.id.tablayout);


        tablayout.addTab(tablayout.newTab().setText("资产"));
        tablayout.addTab(tablayout.newTab().setText("设备"));
        tablayout.addTab(tablayout.newTab().setText("支出"));
        tablayout.addTab(tablayout.newTab().setText("收入"));
        tablayout.addTab(tablayout.newTab().setText("车辆"));
        tablayout.addTab(tablayout.newTab().setText("物流"));
        tablayout.addTab(tablayout.newTab().setText("库存"));


        TabLayoutUtil.dynamicSetTabLayoutMode(tablayout);

第二:我们写好的控件与网页进行交互。

首先我们应该知道安卓手机显示网页用的是webview控件。
我们直接在layout中添加

<WebView  xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
/>

然后在

WebView webView = (ProgressWebView) findViewById(R.id.webview);

WebSettings webSettings = webView.getSettings();

        //设置支持js
        webSettings.setJavaScriptEnabled(true);
        //webView.loadData("","text/html","UTF-8");

        // 设置可以支持缩放
        webSettings.setSupportZoom(true);
        // 设置出现缩放工具
        webSettings.setBuiltInZoomControls(true);
        webSettings.setDisplayZoomControls(false);
        webSettings.setUseWideViewPort(false);

        webView.setInitialScale(250);

        webSettings.setSavePassword(false);
        webView.loadUrl("http://XXXXXXXXXX/index.html");

OK .我们已经先可以看到网页了。接下去就是我们点击我们原生的按钮的时候,可以去让这个网页发生变化。让网页发生变化其实就是网页端调用js方法来让页面动态发生变化,那问题就知道了。我们的java就远程调用JS的方法不就OK了么。

所以上面的Spinner点击事件中,我们选了某个选项,然后调用下面的方法就等于调用了js方法。

webView.post(new Runnable() {
    @Override
    public void run() {
        //loadMap就是js处写的方法的名字,要一模一样。
        webView.loadUrl("javascript:loadMap("+"这里是要转的参数"+")");
        //如果没有参数就直接写方法loadMap()即可
    }
});

这样我们就成功调用了JS方法,重而更改了页面的数据。

有些需求是要JS回调我们这边JAVA的方法,这个项目中,我们用户登录界面等都是在网页处的,但是要求我们这个原生App的外壳本身要有自动登录功能,登录一次后就不需要在网页上再次登录。所以在用户网页里面第一次登录后。那边JS 判断客户成功把账号和处理过的密码发给我们这个原生APP,也就是回调我们这边JAVA写好的方法,然后我们拿到了账号和处理过的密码,保存到本地,比如Sharepreference中,下次客户再打开,我们用原生App去SharePreference中查看是否有账号密码存在,如果存在,就直接调用js的登录方法,把账号密码传入即可。webview里面的页面就自动转到了首页中了。同理用户在网页里面的个人中心修改了密码。也是要再次回调我们的java方法,把新的密码发给我们。

/**
     * 获取密码 
     */
    @JavascriptInterface
    public void getPassword(final String password){
        webView.post(new Runnable() {
            @Override
            public void run() {
                webView.loadUrl(userName);
            }
        });
    }

上面的 @JavascriptInterface是一定要写的。
然后再调用

webView.addJavascriptInterface(this,"webtest");

这里的webtest是随便取名字,等会js调用的时候跟我们这里写的名字一样即可。

然后js处调用:

window.webtest.getPassword(XXXXX)就可以了。

附上一些别人的webview的介绍:Android Webview总结

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容