HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

轻松e购-wap2app项目分享

案例 wap2app

APP名称:轻松e购
已经实现的功能:
一、原生分享;
二、下拉刷新;
三、APP内更新安装;
四、个推推送;
五、清理缓存;
六、阿里百川回调
七、收藏按钮点击刷新

已上架360和酷安,360因无软著,暂时未提交新版本
APP下载地址:APP下载

继续阅读 »

APP名称:轻松e购
已经实现的功能:
一、原生分享;
二、下拉刷新;
三、APP内更新安装;
四、个推推送;
五、清理缓存;
六、阿里百川回调
七、收藏按钮点击刷新

已上架360和酷安,360因无软著,暂时未提交新版本
APP下载地址:APP下载

收起阅读 »

单张拍照 和多张图片选择

<!DOCTYPE html>
<html>

<head>  
    <meta charset="utf-8">  
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
    <title></title>  
    <link href="../css/mui.min.css" rel="stylesheet" />  
    <link href="../css/iconfont.css" rel="stylesheet" />  
    <link href="../css/common.css" rel="stylesheet" />  
    <link href="../css/style.css" rel="stylesheet" />  
    <script src="../js/mui.min.js"></script>  
    <script src="../js/public.js"></script>  
    <script src="../js/common.js"></script>  
    <script src="../js/vue.min.js"></script>  
    <script src="../js/canvasResize.js" type="text/javascript" charset="utf-8"></script>  
    <script src="../js/binaryajax.js" type="text/javascript" charset="utf-8"></script>  
    <script src="../js/exif.js" type="text/javascript" charset="utf-8"></script>  
</head>  

<body>  
    <div id="take_order">  

        <div class="bg-y-ffcc00 padding-10 wxrow">  
            <div class="flex1 b-333">  
                运单号:xxxxx  
            </div>  
            <div class="wxaround" onclick="clicked('barcode_scan.html',true,true)">  
                <span class="iconfont icon-saoma g-009999 size18"></span>  
            </div>  
        </div>  

        <div class="bg-w-fff padding-10 margin-t10">  
            <div class="bold">  
                地址信息  
            </div>  
            <div class='send-view margin-t20'>  
                <div class='send-tips'>寄</div>  
                <div class='triangle-left'></div>  
                <div class='triangle-right'></div>  
                <div class='import-view' data-type="consigner">  
                    <span class='iconfont icon-daoru margin-r5'></span>  
                    <span class='size12'>导入</span>  
                </div>  
                <div class='margin-t20 wxrow b-333'>  
                    <div class='wxaround size12'>姓名:</div>  
                    <div class='flex2 padding-r10'>  
                        <input type='text' class='send-input consigner-name' v-model="consignerName" placeholder='请输入姓名'></input>  
                    </div>  
                    <div class='wxaround size12'>手机:</div>  
                    <div class='flex3'>  
                        <input type='number' class='send-input consigner-phone' v-model="consignerPhone" placeholder='请输入手机'></input>  
                    </div>  
                </div>  
                <div class='margin-t20 wxrow b-333'>  
                    <div class='wxaround size12'>详细地址:</div>  
                    <div class='flex2 padding-r10'>  
                        <input type='text' class='send-input consigner-address' v-model="consignerAddress" placeholder='请输入详细地址'></input>  
                    </div>  
                    <div class='fix-add wxaround select-address' data-type="consigner-address">  
                        <input type="hidden" class="consigner-address-lng" />  
                        <input type="hidden" class="consigner-address-lat" />  
                        <span class='iconfont icon-dingwei size18'></span>  
                    </div>  
                </div>  
                <div class='margin-t20 wxrow b-333'>  
                    <div class='wxaround size12'>身份证号:</div>  
                    <div class='flex2'>  
                        <input type='text' class='send-input' v-model="consignerIdCard" placeholder='请输入身份证号'></input>  
                    </div>  
                </div>  
            </div>  

            <div class='send-view margin-t30'>  
                <div class='send-tips collect-tips'>收</div>  
                <div class='triangle-left collect-triangle-left'></div>  
                <div class='triangle-right collect-triangle-right'></div>  
                <div class='import-view' data-type="consignee">  
                    <span class='iconfont icon-daoru margin-r5'></span>  
                    <span class='size12'>导入</span>  
                </div>  
                <div class='margin-t20 wxrow b-333'>  
                    <div class='wxaround size12'>姓名:</div>  
                    <div class='flex2 padding-r10'>  
                        <input type='text' class='send-input consignee-name' v-model="consigneeName" placeholder='请输入姓名'></input>  
                    </div>  
                    <div class='wxaround size12'>手机:</div>  
                    <div class='flex3'>  
                        <input type='number' class='send-input consignee-phone' v-model="consigneePhone" placeholder='请输入手机'></input>  
                    </div>  
                </div>  
                <div class='margin-t20 wxrow b-333'>  
                    <div class='wxaround size12'>详细地址:</div>  
                    <div class='flex2 padding-r10'>  
                        <input type='text' class='send-input consignee-address' v-model="consigneeAddress" placeholder='请输入详细地址'></input>  
                    </div>  
                    <div class='fix-add wxaround select-address' data-type="consignee-address">  
                        <input type="hidden" class="consignee-address-lng" />  
                        <input type="hidden" class="consignee-address-lat" />  
                        <span class='iconfont icon-dingwei size18'></span>  
                    </div>  
                </div>  
            </div>  
        </div>  

        <div class="bg-w-fff padding-10 margin-t10">  
            <div class="bold">  
                物品信息  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxaround width50 size12'>名称</div>  
                <div class='flex1'>  
                    <input type='text' class='send-input' v-model="goodName" placeholder='请输入名称'></input>  
                </div>  
                <div class='wxaround width50 size12'>类型</div>  
                <div class='flex1 relative'>  
                    <select class="mui-btn send-select">  
                        <option>请选择类型</option>  
                        <option value="item-1">item-1</option>  
                        <option value="item-2">item-2</option>  
                        <option value="item-3">item-3</option>  
                        <option value="item-4">item-4</option>  
                        <option value="item-5">item-5</option>  
                    </select>  
                    <span class="iconfont icon-xiajiantou po-down"></span>  
                </div>  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxaround width50 size12'>重量</div>  
                <div class='flex1 relative'>  
                    <input type='text' class='send-input' placeholder='请输入重量'></input>  
                    <span class="po-down">kg</span>  
                </div>  
                <div class='wxaround width50 size12'>数量</div>  
                <div class='flex1'>  
                    <input type='text' class='send-input' placeholder='请输入名称'></input>  
                </div>  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxaround width50 size12'>打包费  
                </div>  
                <div class='flex1 relative'>  
                    <select class="mui-btn send-select">  
                        <option>请选择类型</option>  
                        <option value="item-1">item-1</option>  
                        <option value="item-2">item-2</option>  
                        <option value="item-3">item-3</option>  
                        <option value="item-4">item-4</option>  
                        <option value="item-5">item-5</option>  
                    </select>  
                    <span class="iconfont icon-xiajiantou po-down"></span>  
                </div>  
                <div class='wxaround width50 size12'>保价费</div>  
                <div class='flex1 relative'>  
                    <input type='text' class='send-input' placeholder='请输入保价费'></input>  
                    <span class="po-down">元</span>  
                </div>  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxaround width50 size12'>备注</div>  
                <div class='flex1 relative'>  
                    <input type='text' class='send-input' placeholder='请输入备注'></input>  
                </div>  
            </div>  
        </div>  

        <div class="bg-w-fff padding-10 margin-t10">  
            <div class="bold">  
                费用信息  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxcenter width60 size12'>计费模式</div>  
                <div class='flex1 relative'>  
                    <select class="mui-btn send-select" v-model="billModel">  
                        <option>请选择计费模式</option>  
                        <option value="item-1">计费-1</option>  
                        <option value="item-2">计费-2</option>  
                        <option value="item-3">计费-3</option>  
                        <option value="item-4">item-4</option>  
                        <option value="item-5">item-5</option>  
                    </select>  
                    <span class="iconfont icon-xiajiantou po-down"></span>  
                </div>  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxcenter width60 size12'>关闭月结</div>  
                <div class='flex1'>  
                    <div class="mui-switch " id="mySwitch">  
                        <div class="mui-switch-handle"></div>  
                    </div>  
                </div>  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxcenter width60 size12'>费用总计</div>  
                <div class='flex1'>  
                    <span class="bold">25.50元</span>  
                </div>  
            </div>  
        </div>  

        <div class="bg-w-fff padding-10 margin-t10">  
            <div class="bold">  
                拍摄照片  
            </div>  
            <div class='margin-t10 wxrow img-list'>  
                <!--<img src="../img/bc-img1.png" class="send-img" />  
                <img src="../img/ceshi.jpg" class="send-img" />  
                <img src="../img/head.png" class="send-img" />  
                <img src="../img/head.png" class="send-img" />  
                <img src="../img/head.png" class="send-img" />  
                <img src="../img/head.png" class="send-img" />-->  
                <!--<img  id="showImg" src="../img/head.png" class="send-img" />-->  
                <div class="send-img add-img" onclick="captureImage()">  
                    <div class="send-img-choose-inside wxaround">  
                        <span class="iconfont icon-tubiao_huabanfuben size20 b-999"></span>  
                    </div>  
                </div>  
            </div>  
        </div>  

        <div class="padding-10">  
            <button type="button" class="btn-take">下单</button>  
        </div>  
    </div>  
    <script>  
        mui.init();  

        function getDefaultData() {  
            return {  
                //寄件人  
                consignerName: '',  
                consignerPhone: '',  
                consignerAddress: '',  
                consignerIdCard: '',  

                //收件人  
                consigneeName: '',  
                consigneePhone: '',  
                consigneeAddress: '',  

                //物品信息  
                goodName: '',  
                goodType: '',  
                goodWeight: '',  
                goodAmount: '',  
                goodPack: '',  
                goodOffer: '',  
                goodRemark: '',  

                billModel: ''  
            }  
        }  

        let take_order = new Vue({  
            el: '#take_order',  
            data: getDefaultData(),  
            methods: {  
                resetData: function() { //重置数据  
                    Object.assign(this.$data, getDefaultData());  
                }  
            }  
        });  

        function clearView() {  
            mui.plusReady(function() {  
                var view = plus.nativeObj.View.getViewById('view');  
                var view1 = plus.nativeObj.View.getViewById('view1');  
                if(view) {  
                    view.close();  
                    view1.close();  
                }  
            })  

        }  

        //导入地址信息  
        function importInfo(t, n, p, d) {  
            if(t == 'consigner') {  
                take_order.consignerName = n;  
                take_order.consignerPhone = p  
                take_order.consignerAddress = d;  
            }  
            if(t == 'consignee') {  
                take_order.consigneeName = n;  
                take_order.consigneePhone = p  
                take_order.consigneeAddress = d;  
            }  
        }  

        function scaned(t, r, f) {  
            console.log(t)  
            console.log(r)  
            console.log(f)  
            if(!f || f == 'null') {  
                img.src = '../img/barcode.png';  
            } else {  
                plus.io.resolveLocalFileSystemURL(f, function(entry) {  
                    img.src = entry.toLocalURL();  
                });  
                //      img.src = 'http://localhost:8020/'+f;  
            }  
        }  

        let maxNum = 9;  
        let imgTotalNum = 0;  
        let imgList = null;  
        // 拍照  
        function captureImage() {  
            imgList = ddsd.qsa('.send-img').length - 1;  
            imgTotalNum = maxNum - imgList;  
            let bts = [{  
                title: "拍照",  
                style: "destructive"  
            }, {  
                title: "从相册选择"  
            }];  
            plus.nativeUI.actionSheet({  
                    title: "上传拍摄图片",  
                    cancel: "取消",  
                    buttons: bts  
                },  
                function(e) {  
                    if(e.index == 1) {  
                        let cmr = plus.camera.getCamera();  
                        cmr.captureImage(function(path) {  
                                plus.io.resolveLocalFileSystemURL(path, function(entry) {  
                                    showImg(entry.toLocalURL());  
                                    ddsd.qs('.send-img').style.height = ddsd.qs('.add-img').offsetWidth - 2 + 'px';  
                                }, function(e) {  
                                    ddsd.toast('读取拍照文件错误:' + e.message);  
                                });  
                            },  
                            function(error) {  
                                ddsd.toast("失败: " + error.message);  
                            }, {  
                                filename: '_doc/camera/',  
                                index: 1  
                            }  
                        );  
                    } else if(e.index == 2) {  
                        plus.gallery.pick(function(e) {  
                            for(var i in e.files) {  
                                showImg(e.files[i]);  
                            }  
                        }, function(e) {  
                            console.log("取消选择图片");  
                        }, {  
                            filter: "image",  
                            multiple: true,  
                            system: false,  
                            maximum: imgTotalNum,  
                            onmaxed: function() {  
                                plus.nativeUI.toast('最多可以选择'+ imgTotalNum +'张图片')  
                            }  
                        });  
                    }  
                }  
            );  

        }  
        // 添加播放项  
        function createItem(entry) {  
            let img = document.createElement('img');  
            img.className = 'send-img';  
            img.src = entry.toLocalURL();  
            ddsd.qs('.img-list').insertBefore(img, ddsd.qs('.img-list').firstChild);  
        }  

        var f1 = new Array();  
        let previewImageList = [];  
        function showImg(url) {  
            plus.nativeUI.showWaiting( "加载中..." );  
            if ((imgList - 1) > 0) {  
                imgTotalNum = imgTotalNum - (imgList - 1);  
            }  
            // 兼容以“file:”开头的情况  
            if(0 != url.toString().indexOf("file://")) {  
                url = "file://" + url;  
            }  
            var _div_ = ddsd.qs('.img-list');  
            var _img_ = new Image();  
            _img_.src = url; // 传过来的图片路径在这里用。  
            _img_.className = 'send-img';  
            _img_.onclick = function() {  
                console.log(f1)  
                plus.nativeUI.previewImage(previewImageList,{  
                    current:0,  
                    loop:true  
                });  
            };  
            _img_.onload = function() {  
                var tmph = _img_.height;  
                var tmpw = _img_.width;  
                var isHengTu = tmpw > tmph;  
                var max = Math.max(tmpw, tmph);  
                var min = Math.min(tmpw, tmph);  
                var bili = min / max;  
                if(max > 1200) {  
                    max = 1200;  
                    min = Math.floor(bili * max);  
                }  
                tmph = isHengTu ? min : max;  
                tmpw = isHengTu ? max : min;  
                _img_.style.height = ddsd.qs('.add-img').offsetWidth - 2 + 'px';  
                _img_.onload = null;  
                plus.io.resolveLocalFileSystemURL(url, function(entry) {  
                        entry.file(function(file) {  
                            ddsd.log(file)  
                            canvasResize(file, {  
                                width: tmpw,  
                                height: tmph,  
                                crop: false,  
                                quality: 50, //压缩质量  
                                rotate: 0,  
                                callback: function(data, width, height) {  
                                    f1.push(data);  
                                    _img_.src = data;  
                                    _div_.appendChild(_img_);  
                                    previewImageList.push(file.fullPath)  
                                    if ((ddsd.qsa('.send-img').length - 1) == 9) {  
                                        ddsd.qs('.add-img').style.display = 'none';  
                                    }  
                                    plus.nativeUI.closeWaiting();  
                                }  
                            });  
                        });  
                    },  
                    function(e) {  
                        plus.nativeUI.closeWaiting();  
                        console.log(e.message);  
                    });  
            };  
        };  

        mui.plusReady(function() {  

            var img = null;  

            function update(t, r, f) {  
                outSet('扫描成功:');  
                outLine(t);  
                outLine(r);  
                outLine('\n图片地址:' + f);  
                if(!f || f == 'null') {  
                    img.src = '../img/barcode.png';  
                } else {  
                    plus.io.resolveLocalFileSystemURL(f, function(entry) {  
                        img.src = entry.toLocalURL();  
                    });  
                    //img.src = 'http://localhost:13131/'+f;  
                }  
            }  

            document.getElementById("mySwitch").addEventListener("toggle", function(event) {  
                if(event.detail.isActive) {  
                    console.log("你启动了开关");  
                } else {  
                    console.log("你关闭了开关");  
                }  
            })  

            var alist = document.getElementsByClassName("send-img");  
            if(alist) {  
                for(var i = 0; i < alist.length; i++) {  
                    alist[i].style.height = alist[i].offsetWidth + "px";;  
                }  
            }  

            //导入发货信息  
            mui("body").on('tap', '.import-view', function(e) {  
                var type = this.dataset.type;  
                var webview = mui.openWindow({  
                    url: 'search_add.html',  
                    id: 'search_add.html',  
                    styles: { // 窗口参数 参考5+规范中的WebviewStyle,也就是说WebviewStyle下的参数都可以在此设置  
                        titleNView: { // 窗口的标题栏控件  
                            autoBackButton: true,  
                            titleText: '查询地址', // 标题栏文字,当不设置此属性时,默认加载当前页面的标题,并自动更新页面的标题  
                            titleColor: "#000000", // 字体颜色,颜色值格式为"#RRGGBB",默认值为"#000000"  
                            titleSize: "17px", // 字体大小,默认17px  
                            backgroundColor: "#FFCC00", // 控件背景颜色,颜色值格式为"#RRGGBB",默认值为"#F7F7F7"  
                        }  
                    },  
                    extras: {  
                        type: type  
                    }  
                });  
            })  

            //获取地址信息  
            mui("body").on('tap', '.select-address', function(e) {  
                var address = document.querySelector('.' + this.dataset.type).value;  
                var type = this.dataset.type;  
                if('Android' === plus.os.name && navigator.userAgent.indexOf('StreamApp') > 0) {  
                    plus.nativeUI.toast('当前环境暂不支持地图插件');  
                    return;  
                }  
                var ws = plus.webview.currentWebview();  
                var wm = plus.webview.getWebviewById(plus.runtime.appid);  
                wm && wm.evalJS("preateClear()");  
                var subpage = mui.openWindow({  
                    url: 'maps_map.html',  
                    id: 'maps_map.html',  
                    styles: { // 窗口参数 参考5+规范中的WebviewStyle,也就是说WebviewStyle下的参数都可以在此设置  
                        titleNView: { // 窗口的标题栏控件  
                            autoBackButton: true,  
                            titleText: '位置信息', // 标题栏文字,当不设置此属性时,默认加载当前页面的标题,并自动更新页面的标题  
                            titleColor: "#000000", // 字体颜色,颜色值格式为"#RRGGBB",默认值为"#000000"  
                            titleSize: "17px", // 字体大小,默认17px  
                            backgroundColor: "#FFCC00", // 控件背景颜色,颜色值格式为"#RRGGBB",默认值为"#F7F7F7"  
                        }  
                    },  
                    extras: {  
                        address: address,  
                        type: type  
                    }  
                });  

                //页面转场的时候清除掉view。  
                subpage.addEventListener('loaded', function() {  
                    subpage.show('slide-in-right', 200, function() {  
                        view.clear();  
                        view1.clear();  
                    });  
                });  
            })  

            //下单  
            mui("body").on('tap', '.btn-take', function() {  

                //                  if(!take_order.consignerName.Trim()) {  
                //                      ddsd.toast('请输入寄件人姓名');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consignerPhone.Trim()) {  
                //                      ddsd.toast('请输入寄件人电话');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consignerAddress.Trim()) {  
                //                      ddsd.toast('请输入寄件人地址');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consignerIdCard.Trim()) {  
                //                      ddsd.toast('请输入寄件人身份证');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consigneeName.Trim()) {  
                //                      ddsd.toast('请输入收件人姓名');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consigneePhone.Trim()) {  
                //                      ddsd.toast('请输入收件人手机');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consigneeAddress.Trim()) {  
                //                      ddsd.toast('请输入收件人地址');  
                //                      return false;  
                //                  }  

                console.log(take_order.billModel)  
                /*                  mui.openWindow({  
                                        url: 'wait_pay.html',  
                                        id: 'wait_pay.html',  
                                        styles: { // 窗口参数 参考5+规范中的WebviewStyle,也就是说WebviewStyle下的参数都可以在此设置  
                                            titleNView: { // 窗口的标题栏控件  
                                                autoBackButton: true,  
                                                titleText: '等待支付', // 标题栏文字,当不设置此属性时,默认加载当前页面的标题,并自动更新页面的标题  
                                                titleColor: "#000000", // 字体颜色,颜色值格式为"#RRGGBB",默认值为"#000000"  
                                                titleSize: "17px", // 字体大小,默认17px  
                                                backgroundColor: "#FFCC00", // 控件背景颜色,颜色值格式为"#RRGGBB",默认值为"#F7F7F7"  
                                            }  
                                        }  
                                    });*/  
            })  

        })  

        function setAddress() {  
            mui.plusReady(function() {  
                var addressJson = plus.storage.getItem('addressJson')  
                var addressData = JSON.parse(addressJson);  
                document.querySelector('.' + addressData.type).value = addressData.address;  
                document.querySelector('.' + addressData.type + '-lng').value = addressData.longitude;  
                document.querySelector('.' + addressData.type + '-lat').value = addressData.latitude;  
            })  
        }  
    </script>  

</body>  

</html>

继续阅读 »

<!DOCTYPE html>
<html>

<head>  
    <meta charset="utf-8">  
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
    <title></title>  
    <link href="../css/mui.min.css" rel="stylesheet" />  
    <link href="../css/iconfont.css" rel="stylesheet" />  
    <link href="../css/common.css" rel="stylesheet" />  
    <link href="../css/style.css" rel="stylesheet" />  
    <script src="../js/mui.min.js"></script>  
    <script src="../js/public.js"></script>  
    <script src="../js/common.js"></script>  
    <script src="../js/vue.min.js"></script>  
    <script src="../js/canvasResize.js" type="text/javascript" charset="utf-8"></script>  
    <script src="../js/binaryajax.js" type="text/javascript" charset="utf-8"></script>  
    <script src="../js/exif.js" type="text/javascript" charset="utf-8"></script>  
</head>  

<body>  
    <div id="take_order">  

        <div class="bg-y-ffcc00 padding-10 wxrow">  
            <div class="flex1 b-333">  
                运单号:xxxxx  
            </div>  
            <div class="wxaround" onclick="clicked('barcode_scan.html',true,true)">  
                <span class="iconfont icon-saoma g-009999 size18"></span>  
            </div>  
        </div>  

        <div class="bg-w-fff padding-10 margin-t10">  
            <div class="bold">  
                地址信息  
            </div>  
            <div class='send-view margin-t20'>  
                <div class='send-tips'>寄</div>  
                <div class='triangle-left'></div>  
                <div class='triangle-right'></div>  
                <div class='import-view' data-type="consigner">  
                    <span class='iconfont icon-daoru margin-r5'></span>  
                    <span class='size12'>导入</span>  
                </div>  
                <div class='margin-t20 wxrow b-333'>  
                    <div class='wxaround size12'>姓名:</div>  
                    <div class='flex2 padding-r10'>  
                        <input type='text' class='send-input consigner-name' v-model="consignerName" placeholder='请输入姓名'></input>  
                    </div>  
                    <div class='wxaround size12'>手机:</div>  
                    <div class='flex3'>  
                        <input type='number' class='send-input consigner-phone' v-model="consignerPhone" placeholder='请输入手机'></input>  
                    </div>  
                </div>  
                <div class='margin-t20 wxrow b-333'>  
                    <div class='wxaround size12'>详细地址:</div>  
                    <div class='flex2 padding-r10'>  
                        <input type='text' class='send-input consigner-address' v-model="consignerAddress" placeholder='请输入详细地址'></input>  
                    </div>  
                    <div class='fix-add wxaround select-address' data-type="consigner-address">  
                        <input type="hidden" class="consigner-address-lng" />  
                        <input type="hidden" class="consigner-address-lat" />  
                        <span class='iconfont icon-dingwei size18'></span>  
                    </div>  
                </div>  
                <div class='margin-t20 wxrow b-333'>  
                    <div class='wxaround size12'>身份证号:</div>  
                    <div class='flex2'>  
                        <input type='text' class='send-input' v-model="consignerIdCard" placeholder='请输入身份证号'></input>  
                    </div>  
                </div>  
            </div>  

            <div class='send-view margin-t30'>  
                <div class='send-tips collect-tips'>收</div>  
                <div class='triangle-left collect-triangle-left'></div>  
                <div class='triangle-right collect-triangle-right'></div>  
                <div class='import-view' data-type="consignee">  
                    <span class='iconfont icon-daoru margin-r5'></span>  
                    <span class='size12'>导入</span>  
                </div>  
                <div class='margin-t20 wxrow b-333'>  
                    <div class='wxaround size12'>姓名:</div>  
                    <div class='flex2 padding-r10'>  
                        <input type='text' class='send-input consignee-name' v-model="consigneeName" placeholder='请输入姓名'></input>  
                    </div>  
                    <div class='wxaround size12'>手机:</div>  
                    <div class='flex3'>  
                        <input type='number' class='send-input consignee-phone' v-model="consigneePhone" placeholder='请输入手机'></input>  
                    </div>  
                </div>  
                <div class='margin-t20 wxrow b-333'>  
                    <div class='wxaround size12'>详细地址:</div>  
                    <div class='flex2 padding-r10'>  
                        <input type='text' class='send-input consignee-address' v-model="consigneeAddress" placeholder='请输入详细地址'></input>  
                    </div>  
                    <div class='fix-add wxaround select-address' data-type="consignee-address">  
                        <input type="hidden" class="consignee-address-lng" />  
                        <input type="hidden" class="consignee-address-lat" />  
                        <span class='iconfont icon-dingwei size18'></span>  
                    </div>  
                </div>  
            </div>  
        </div>  

        <div class="bg-w-fff padding-10 margin-t10">  
            <div class="bold">  
                物品信息  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxaround width50 size12'>名称</div>  
                <div class='flex1'>  
                    <input type='text' class='send-input' v-model="goodName" placeholder='请输入名称'></input>  
                </div>  
                <div class='wxaround width50 size12'>类型</div>  
                <div class='flex1 relative'>  
                    <select class="mui-btn send-select">  
                        <option>请选择类型</option>  
                        <option value="item-1">item-1</option>  
                        <option value="item-2">item-2</option>  
                        <option value="item-3">item-3</option>  
                        <option value="item-4">item-4</option>  
                        <option value="item-5">item-5</option>  
                    </select>  
                    <span class="iconfont icon-xiajiantou po-down"></span>  
                </div>  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxaround width50 size12'>重量</div>  
                <div class='flex1 relative'>  
                    <input type='text' class='send-input' placeholder='请输入重量'></input>  
                    <span class="po-down">kg</span>  
                </div>  
                <div class='wxaround width50 size12'>数量</div>  
                <div class='flex1'>  
                    <input type='text' class='send-input' placeholder='请输入名称'></input>  
                </div>  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxaround width50 size12'>打包费  
                </div>  
                <div class='flex1 relative'>  
                    <select class="mui-btn send-select">  
                        <option>请选择类型</option>  
                        <option value="item-1">item-1</option>  
                        <option value="item-2">item-2</option>  
                        <option value="item-3">item-3</option>  
                        <option value="item-4">item-4</option>  
                        <option value="item-5">item-5</option>  
                    </select>  
                    <span class="iconfont icon-xiajiantou po-down"></span>  
                </div>  
                <div class='wxaround width50 size12'>保价费</div>  
                <div class='flex1 relative'>  
                    <input type='text' class='send-input' placeholder='请输入保价费'></input>  
                    <span class="po-down">元</span>  
                </div>  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxaround width50 size12'>备注</div>  
                <div class='flex1 relative'>  
                    <input type='text' class='send-input' placeholder='请输入备注'></input>  
                </div>  
            </div>  
        </div>  

        <div class="bg-w-fff padding-10 margin-t10">  
            <div class="bold">  
                费用信息  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxcenter width60 size12'>计费模式</div>  
                <div class='flex1 relative'>  
                    <select class="mui-btn send-select" v-model="billModel">  
                        <option>请选择计费模式</option>  
                        <option value="item-1">计费-1</option>  
                        <option value="item-2">计费-2</option>  
                        <option value="item-3">计费-3</option>  
                        <option value="item-4">item-4</option>  
                        <option value="item-5">item-5</option>  
                    </select>  
                    <span class="iconfont icon-xiajiantou po-down"></span>  
                </div>  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxcenter width60 size12'>关闭月结</div>  
                <div class='flex1'>  
                    <div class="mui-switch " id="mySwitch">  
                        <div class="mui-switch-handle"></div>  
                    </div>  
                </div>  
            </div>  
            <div class='margin-t20 wxrow b-333'>  
                <div class='wxcenter width60 size12'>费用总计</div>  
                <div class='flex1'>  
                    <span class="bold">25.50元</span>  
                </div>  
            </div>  
        </div>  

        <div class="bg-w-fff padding-10 margin-t10">  
            <div class="bold">  
                拍摄照片  
            </div>  
            <div class='margin-t10 wxrow img-list'>  
                <!--<img src="../img/bc-img1.png" class="send-img" />  
                <img src="../img/ceshi.jpg" class="send-img" />  
                <img src="../img/head.png" class="send-img" />  
                <img src="../img/head.png" class="send-img" />  
                <img src="../img/head.png" class="send-img" />  
                <img src="../img/head.png" class="send-img" />-->  
                <!--<img  id="showImg" src="../img/head.png" class="send-img" />-->  
                <div class="send-img add-img" onclick="captureImage()">  
                    <div class="send-img-choose-inside wxaround">  
                        <span class="iconfont icon-tubiao_huabanfuben size20 b-999"></span>  
                    </div>  
                </div>  
            </div>  
        </div>  

        <div class="padding-10">  
            <button type="button" class="btn-take">下单</button>  
        </div>  
    </div>  
    <script>  
        mui.init();  

        function getDefaultData() {  
            return {  
                //寄件人  
                consignerName: '',  
                consignerPhone: '',  
                consignerAddress: '',  
                consignerIdCard: '',  

                //收件人  
                consigneeName: '',  
                consigneePhone: '',  
                consigneeAddress: '',  

                //物品信息  
                goodName: '',  
                goodType: '',  
                goodWeight: '',  
                goodAmount: '',  
                goodPack: '',  
                goodOffer: '',  
                goodRemark: '',  

                billModel: ''  
            }  
        }  

        let take_order = new Vue({  
            el: '#take_order',  
            data: getDefaultData(),  
            methods: {  
                resetData: function() { //重置数据  
                    Object.assign(this.$data, getDefaultData());  
                }  
            }  
        });  

        function clearView() {  
            mui.plusReady(function() {  
                var view = plus.nativeObj.View.getViewById('view');  
                var view1 = plus.nativeObj.View.getViewById('view1');  
                if(view) {  
                    view.close();  
                    view1.close();  
                }  
            })  

        }  

        //导入地址信息  
        function importInfo(t, n, p, d) {  
            if(t == 'consigner') {  
                take_order.consignerName = n;  
                take_order.consignerPhone = p  
                take_order.consignerAddress = d;  
            }  
            if(t == 'consignee') {  
                take_order.consigneeName = n;  
                take_order.consigneePhone = p  
                take_order.consigneeAddress = d;  
            }  
        }  

        function scaned(t, r, f) {  
            console.log(t)  
            console.log(r)  
            console.log(f)  
            if(!f || f == 'null') {  
                img.src = '../img/barcode.png';  
            } else {  
                plus.io.resolveLocalFileSystemURL(f, function(entry) {  
                    img.src = entry.toLocalURL();  
                });  
                //      img.src = 'http://localhost:8020/'+f;  
            }  
        }  

        let maxNum = 9;  
        let imgTotalNum = 0;  
        let imgList = null;  
        // 拍照  
        function captureImage() {  
            imgList = ddsd.qsa('.send-img').length - 1;  
            imgTotalNum = maxNum - imgList;  
            let bts = [{  
                title: "拍照",  
                style: "destructive"  
            }, {  
                title: "从相册选择"  
            }];  
            plus.nativeUI.actionSheet({  
                    title: "上传拍摄图片",  
                    cancel: "取消",  
                    buttons: bts  
                },  
                function(e) {  
                    if(e.index == 1) {  
                        let cmr = plus.camera.getCamera();  
                        cmr.captureImage(function(path) {  
                                plus.io.resolveLocalFileSystemURL(path, function(entry) {  
                                    showImg(entry.toLocalURL());  
                                    ddsd.qs('.send-img').style.height = ddsd.qs('.add-img').offsetWidth - 2 + 'px';  
                                }, function(e) {  
                                    ddsd.toast('读取拍照文件错误:' + e.message);  
                                });  
                            },  
                            function(error) {  
                                ddsd.toast("失败: " + error.message);  
                            }, {  
                                filename: '_doc/camera/',  
                                index: 1  
                            }  
                        );  
                    } else if(e.index == 2) {  
                        plus.gallery.pick(function(e) {  
                            for(var i in e.files) {  
                                showImg(e.files[i]);  
                            }  
                        }, function(e) {  
                            console.log("取消选择图片");  
                        }, {  
                            filter: "image",  
                            multiple: true,  
                            system: false,  
                            maximum: imgTotalNum,  
                            onmaxed: function() {  
                                plus.nativeUI.toast('最多可以选择'+ imgTotalNum +'张图片')  
                            }  
                        });  
                    }  
                }  
            );  

        }  
        // 添加播放项  
        function createItem(entry) {  
            let img = document.createElement('img');  
            img.className = 'send-img';  
            img.src = entry.toLocalURL();  
            ddsd.qs('.img-list').insertBefore(img, ddsd.qs('.img-list').firstChild);  
        }  

        var f1 = new Array();  
        let previewImageList = [];  
        function showImg(url) {  
            plus.nativeUI.showWaiting( "加载中..." );  
            if ((imgList - 1) > 0) {  
                imgTotalNum = imgTotalNum - (imgList - 1);  
            }  
            // 兼容以“file:”开头的情况  
            if(0 != url.toString().indexOf("file://")) {  
                url = "file://" + url;  
            }  
            var _div_ = ddsd.qs('.img-list');  
            var _img_ = new Image();  
            _img_.src = url; // 传过来的图片路径在这里用。  
            _img_.className = 'send-img';  
            _img_.onclick = function() {  
                console.log(f1)  
                plus.nativeUI.previewImage(previewImageList,{  
                    current:0,  
                    loop:true  
                });  
            };  
            _img_.onload = function() {  
                var tmph = _img_.height;  
                var tmpw = _img_.width;  
                var isHengTu = tmpw > tmph;  
                var max = Math.max(tmpw, tmph);  
                var min = Math.min(tmpw, tmph);  
                var bili = min / max;  
                if(max > 1200) {  
                    max = 1200;  
                    min = Math.floor(bili * max);  
                }  
                tmph = isHengTu ? min : max;  
                tmpw = isHengTu ? max : min;  
                _img_.style.height = ddsd.qs('.add-img').offsetWidth - 2 + 'px';  
                _img_.onload = null;  
                plus.io.resolveLocalFileSystemURL(url, function(entry) {  
                        entry.file(function(file) {  
                            ddsd.log(file)  
                            canvasResize(file, {  
                                width: tmpw,  
                                height: tmph,  
                                crop: false,  
                                quality: 50, //压缩质量  
                                rotate: 0,  
                                callback: function(data, width, height) {  
                                    f1.push(data);  
                                    _img_.src = data;  
                                    _div_.appendChild(_img_);  
                                    previewImageList.push(file.fullPath)  
                                    if ((ddsd.qsa('.send-img').length - 1) == 9) {  
                                        ddsd.qs('.add-img').style.display = 'none';  
                                    }  
                                    plus.nativeUI.closeWaiting();  
                                }  
                            });  
                        });  
                    },  
                    function(e) {  
                        plus.nativeUI.closeWaiting();  
                        console.log(e.message);  
                    });  
            };  
        };  

        mui.plusReady(function() {  

            var img = null;  

            function update(t, r, f) {  
                outSet('扫描成功:');  
                outLine(t);  
                outLine(r);  
                outLine('\n图片地址:' + f);  
                if(!f || f == 'null') {  
                    img.src = '../img/barcode.png';  
                } else {  
                    plus.io.resolveLocalFileSystemURL(f, function(entry) {  
                        img.src = entry.toLocalURL();  
                    });  
                    //img.src = 'http://localhost:13131/'+f;  
                }  
            }  

            document.getElementById("mySwitch").addEventListener("toggle", function(event) {  
                if(event.detail.isActive) {  
                    console.log("你启动了开关");  
                } else {  
                    console.log("你关闭了开关");  
                }  
            })  

            var alist = document.getElementsByClassName("send-img");  
            if(alist) {  
                for(var i = 0; i < alist.length; i++) {  
                    alist[i].style.height = alist[i].offsetWidth + "px";;  
                }  
            }  

            //导入发货信息  
            mui("body").on('tap', '.import-view', function(e) {  
                var type = this.dataset.type;  
                var webview = mui.openWindow({  
                    url: 'search_add.html',  
                    id: 'search_add.html',  
                    styles: { // 窗口参数 参考5+规范中的WebviewStyle,也就是说WebviewStyle下的参数都可以在此设置  
                        titleNView: { // 窗口的标题栏控件  
                            autoBackButton: true,  
                            titleText: '查询地址', // 标题栏文字,当不设置此属性时,默认加载当前页面的标题,并自动更新页面的标题  
                            titleColor: "#000000", // 字体颜色,颜色值格式为"#RRGGBB",默认值为"#000000"  
                            titleSize: "17px", // 字体大小,默认17px  
                            backgroundColor: "#FFCC00", // 控件背景颜色,颜色值格式为"#RRGGBB",默认值为"#F7F7F7"  
                        }  
                    },  
                    extras: {  
                        type: type  
                    }  
                });  
            })  

            //获取地址信息  
            mui("body").on('tap', '.select-address', function(e) {  
                var address = document.querySelector('.' + this.dataset.type).value;  
                var type = this.dataset.type;  
                if('Android' === plus.os.name && navigator.userAgent.indexOf('StreamApp') > 0) {  
                    plus.nativeUI.toast('当前环境暂不支持地图插件');  
                    return;  
                }  
                var ws = plus.webview.currentWebview();  
                var wm = plus.webview.getWebviewById(plus.runtime.appid);  
                wm && wm.evalJS("preateClear()");  
                var subpage = mui.openWindow({  
                    url: 'maps_map.html',  
                    id: 'maps_map.html',  
                    styles: { // 窗口参数 参考5+规范中的WebviewStyle,也就是说WebviewStyle下的参数都可以在此设置  
                        titleNView: { // 窗口的标题栏控件  
                            autoBackButton: true,  
                            titleText: '位置信息', // 标题栏文字,当不设置此属性时,默认加载当前页面的标题,并自动更新页面的标题  
                            titleColor: "#000000", // 字体颜色,颜色值格式为"#RRGGBB",默认值为"#000000"  
                            titleSize: "17px", // 字体大小,默认17px  
                            backgroundColor: "#FFCC00", // 控件背景颜色,颜色值格式为"#RRGGBB",默认值为"#F7F7F7"  
                        }  
                    },  
                    extras: {  
                        address: address,  
                        type: type  
                    }  
                });  

                //页面转场的时候清除掉view。  
                subpage.addEventListener('loaded', function() {  
                    subpage.show('slide-in-right', 200, function() {  
                        view.clear();  
                        view1.clear();  
                    });  
                });  
            })  

            //下单  
            mui("body").on('tap', '.btn-take', function() {  

                //                  if(!take_order.consignerName.Trim()) {  
                //                      ddsd.toast('请输入寄件人姓名');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consignerPhone.Trim()) {  
                //                      ddsd.toast('请输入寄件人电话');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consignerAddress.Trim()) {  
                //                      ddsd.toast('请输入寄件人地址');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consignerIdCard.Trim()) {  
                //                      ddsd.toast('请输入寄件人身份证');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consigneeName.Trim()) {  
                //                      ddsd.toast('请输入收件人姓名');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consigneePhone.Trim()) {  
                //                      ddsd.toast('请输入收件人手机');  
                //                      return false;  
                //                  }  
                //                  if(!take_order.consigneeAddress.Trim()) {  
                //                      ddsd.toast('请输入收件人地址');  
                //                      return false;  
                //                  }  

                console.log(take_order.billModel)  
                /*                  mui.openWindow({  
                                        url: 'wait_pay.html',  
                                        id: 'wait_pay.html',  
                                        styles: { // 窗口参数 参考5+规范中的WebviewStyle,也就是说WebviewStyle下的参数都可以在此设置  
                                            titleNView: { // 窗口的标题栏控件  
                                                autoBackButton: true,  
                                                titleText: '等待支付', // 标题栏文字,当不设置此属性时,默认加载当前页面的标题,并自动更新页面的标题  
                                                titleColor: "#000000", // 字体颜色,颜色值格式为"#RRGGBB",默认值为"#000000"  
                                                titleSize: "17px", // 字体大小,默认17px  
                                                backgroundColor: "#FFCC00", // 控件背景颜色,颜色值格式为"#RRGGBB",默认值为"#F7F7F7"  
                                            }  
                                        }  
                                    });*/  
            })  

        })  

        function setAddress() {  
            mui.plusReady(function() {  
                var addressJson = plus.storage.getItem('addressJson')  
                var addressData = JSON.parse(addressJson);  
                document.querySelector('.' + addressData.type).value = addressData.address;  
                document.querySelector('.' + addressData.type + '-lng').value = addressData.longitude;  
                document.querySelector('.' + addressData.type + '-lat').value = addressData.latitude;  
            })  
        }  
    </script>  

</body>  

</html>

收起阅读 »

NFC读取卡片ID

NFC Native.JS

本人小白一枚,在基于@Android_磊子大哥的文章(原文地址)以及网上的一些大神的文章,改了一点自己需要的功能

<!DOCTYPE html>  
<html>  
    <head>  
        <meta charset="utf-8">  
        <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>  
        <title></title>  
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>  
        <script>  
            var NfcAdapter;  
            var NdefRecord;  
            var NdefMessage;  
            function listenNFCStatus() {  
                try{  
                    var main = plus.android.runtimeMainActivity();  
                    var Intent = plus.android.importClass('android.content.Intent');  
                    var Activity = plus.android.importClass('android.app.Activity');  
                    var PendingIntent = plus.android.importClass('android.app.PendingIntent');  
                    var IntentFilter = plus.android.importClass('android.content.IntentFilter');  
                    NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');  
                    var nfcAdapter = NfcAdapter.getDefaultAdapter(main);  
                    var intent = new Intent(main, main.getClass());  
                    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);  
                    var pendingIntent = PendingIntent.getActivity(main, 0, intent, 0);  
                    var ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED");  
                    ndef.addDataType("*/*");  
                    var intentFiltersArray = [ndef];  
                    var techListsArray = [  
                        ["android.nfc.tech.IsoDep"],  
                        ["android.nfc.tech.NfcA"],  
                        ["android.nfc.tech.NfcB"],  
                        ["android.nfc.tech.NfcF"],  
                        ["android.nfc.tech.Nfcf"],  
                        ["android.nfc.tech.NfcV"],  
                        ["android.nfc.tech.NdefFormatable"],  
                        ["android.nfc.tech.MifareClassic"],  
                        ["android.nfc.tech.MifareUltralight"]  
                    ];  
                    document.addEventListener("newintent",  
                        function() {  
                            console.error('newintent');  
                            setTimeout(handle_nfc_data1, 1000);  
                        }, false);  
                    document.addEventListener("pause", function(e) {  
                        if (nfcAdapter) {  
                            nfcAdapter.disableForegroundDispatch(main);  
                            console.log('pause');  
                        }  
                    }, false);  
                    document.addEventListener("resume", function(e) {  
                        if (nfcAdapter) {  
                            console.log('resume');  
                            nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);  
                        }  
                    }, false);  
                    nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);  
                }catch(e){  
                    console.error(e);  
                }  
            }  

            function handle_nfc_data1()  
            {  
                NdefRecord = plus.android.importClass("android.nfc.NdefRecord");  
                NdefMessage = plus.android.importClass("android.nfc.NdefMessage");  
                var main = plus.android.runtimeMainActivity();  
                var intent = main.getIntent();  
                console.log("action type:" + intent.getAction());  
                if("android.nfc.action.TECH_DISCOVERED" == intent.getAction()){  
                    if(readyWriteData){  
                        __write(intent);  
                        readyWriteData = false;  
                    }else if(readyRead){  
                        __read(intent);  
                        readyRead = false;  
                    }  
                }  
            }  
            function showToast(msg){  
                plus.nativeUI.toast(msg);  
            }  

            function __write(intent){  
                try{  
                    waiting.setTitle('请勿移开标签\n正在写入...');  
                    var text = document.getElementById('text').value;  
                    console.log("text=" + text);  
                    var textBytes = plus.android.invoke(text,"getBytes");  
                    var textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA,  
                            plus.android.invoke("text/plain","getBytes"), plus.android.invoke("","getBytes"), textBytes);  
                    var message = new NdefMessage([textRecord]);  
                    var Ndef = plus.android.importClass('android.nfc.tech.Ndef');  
                    var NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');  
                    var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
                    var ndef = Ndef.get(tag);  
                    if (ndef != null) {  
                        var size = message.toByteArray().length;  
                        console.log("size=" + size);  
                        ndef.connect();  
                        if (!ndef.isWritable()) {  
                            showToast("tag不允许写入");  
                            waiting.close();  
                            return ;  
                        }  
                        if (ndef.getMaxSize() < size) {  
                            showToast("文件大小超出容量");  
                            waiting.close();  
                            return ;  
                        }  

                        ndef.writeNdefMessage(message);  
                        waiting.close();  
                        showToast("写入数据成功.");  
                        return ;  
                    } else {  
                        var format = NdefFormatable.get(tag);  
                        if (format != null) {  
                            try {  
                                format.connect();  
                                format.format(message);  
                                showToast("格式化tag并且写入message");  
                                waiting.close();  
                                return ;  
                            } catch (e) {  
                                showToast("格式化tag失败.");  
                                waiting.close();  
                                return ;  
                            }  
                        } else {  
                            showToast("Tag不支持NDEF");  
                            waiting.close();  
                            return ;  
                        }  
                    }  
                }catch(e){  
                    console.log("error=" + e);  
                    waiting.close();  
                    alert('写入失败');  
                }  

            }  

            function __read(intent){  
                try{  
                    var content = "";  
                    waiting.setTitle('请勿移开标签\n正在读取数据...');  
                    var tag = plus.android.importClass("android.nfc.Tag");  
                    tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
                    var bytesId  = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);  
                    console.log("bytesId:"+(bytesId));  
                    waiting.close();  
                    content +="卡片字节数组ID:"+tag.getId()+"<br/>";  
                    content +="卡片16进制ID:"+ bytesToHexString(tag.getId())+"<br/>";  
                    var tagid = reverseTwo(bytesToHexString(tag.getId()));  
                    content +="卡片16进制翻转ID:"+tagid+"<br/>";  
                    content +="卡片10进制卡号:"+parseInt(tagid, 16)+"<br/>";  

                    $("#content").html(content);  

                }catch(e){  
                    alert(e);  
                    //TODO handle the exception  
                }  
            }  

            function bytesToHexString(inarray){  
                var i, j, x;  
                var hex = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",  
                    "B", "C", "D", "E", "F" ];  
                var out = "";  
                for (j = 0; j < inarray.length; ++j) {  
                    x = parseInt(inarray[j]) & 0xff;  
                    i = (x >> 4) & 0x0f;  
                    out += hex[i];  
                    i = x & 0x0f;  
                    out += hex[i];  
                }  
                return out;  
            }  

            function reverseTwo(str)   
            {   

                var str1 = "";  
                for(var i = 1; i <= str.length; i++){  
                    str1 +=str[i-1];  
                    if(i%2==0){  
                        if(i == str.length){  
                            break;  
                        }  
                        str1+=":";  
                    }  
                }  
                var str2 = "";  
                for(var i = str1.split(":").length-1; i >= 0 ; i--){  
                    str2+= str1.split(":")[i];  
                }  
                return str2;  
            }  

            document.addEventListener('plusready',listenNFCStatus,false);  

            var waiting ;  
            var readyWriteData = false;  
            var readyRead = false;  
            function writeData(){  
                var textEle = document.getElementById('text');  
                if(!textEle.value){  
                    alert('请输入要写入的内容');  
                    return;  
                }  
                readyWriteData = true;  
                waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");  
            }  
            function readData(){  
                readyRead = true;  
                waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");  
            }  
        </script>  

        <style>  
            button{  
                width: 50%;  
                height: 50px;  
            }  
        </style>  
    </head>  
    <body>  
        输入要写入的内容:<br/><textarea id="text">姓名:张二蛋年龄:29地址:北京海淀区</textarea><br/>  
       <button onclick="writeData()">写入</button>  
        <button style="position: absolute; bottom: 100px; right: 100px;" onclick="readData()">读取</button><br/>  
        读取的内容:  
        <div id="content"/>  
    </body>  
</html>

manifest.json 模块权限配置勾选了NFC
避免打包之后刷卡会闪退

继续阅读 »

本人小白一枚,在基于@Android_磊子大哥的文章(原文地址)以及网上的一些大神的文章,改了一点自己需要的功能

<!DOCTYPE html>  
<html>  
    <head>  
        <meta charset="utf-8">  
        <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>  
        <title></title>  
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>  
        <script>  
            var NfcAdapter;  
            var NdefRecord;  
            var NdefMessage;  
            function listenNFCStatus() {  
                try{  
                    var main = plus.android.runtimeMainActivity();  
                    var Intent = plus.android.importClass('android.content.Intent');  
                    var Activity = plus.android.importClass('android.app.Activity');  
                    var PendingIntent = plus.android.importClass('android.app.PendingIntent');  
                    var IntentFilter = plus.android.importClass('android.content.IntentFilter');  
                    NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter');  
                    var nfcAdapter = NfcAdapter.getDefaultAdapter(main);  
                    var intent = new Intent(main, main.getClass());  
                    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);  
                    var pendingIntent = PendingIntent.getActivity(main, 0, intent, 0);  
                    var ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED");  
                    ndef.addDataType("*/*");  
                    var intentFiltersArray = [ndef];  
                    var techListsArray = [  
                        ["android.nfc.tech.IsoDep"],  
                        ["android.nfc.tech.NfcA"],  
                        ["android.nfc.tech.NfcB"],  
                        ["android.nfc.tech.NfcF"],  
                        ["android.nfc.tech.Nfcf"],  
                        ["android.nfc.tech.NfcV"],  
                        ["android.nfc.tech.NdefFormatable"],  
                        ["android.nfc.tech.MifareClassic"],  
                        ["android.nfc.tech.MifareUltralight"]  
                    ];  
                    document.addEventListener("newintent",  
                        function() {  
                            console.error('newintent');  
                            setTimeout(handle_nfc_data1, 1000);  
                        }, false);  
                    document.addEventListener("pause", function(e) {  
                        if (nfcAdapter) {  
                            nfcAdapter.disableForegroundDispatch(main);  
                            console.log('pause');  
                        }  
                    }, false);  
                    document.addEventListener("resume", function(e) {  
                        if (nfcAdapter) {  
                            console.log('resume');  
                            nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);  
                        }  
                    }, false);  
                    nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray);  
                }catch(e){  
                    console.error(e);  
                }  
            }  

            function handle_nfc_data1()  
            {  
                NdefRecord = plus.android.importClass("android.nfc.NdefRecord");  
                NdefMessage = plus.android.importClass("android.nfc.NdefMessage");  
                var main = plus.android.runtimeMainActivity();  
                var intent = main.getIntent();  
                console.log("action type:" + intent.getAction());  
                if("android.nfc.action.TECH_DISCOVERED" == intent.getAction()){  
                    if(readyWriteData){  
                        __write(intent);  
                        readyWriteData = false;  
                    }else if(readyRead){  
                        __read(intent);  
                        readyRead = false;  
                    }  
                }  
            }  
            function showToast(msg){  
                plus.nativeUI.toast(msg);  
            }  

            function __write(intent){  
                try{  
                    waiting.setTitle('请勿移开标签\n正在写入...');  
                    var text = document.getElementById('text').value;  
                    console.log("text=" + text);  
                    var textBytes = plus.android.invoke(text,"getBytes");  
                    var textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA,  
                            plus.android.invoke("text/plain","getBytes"), plus.android.invoke("","getBytes"), textBytes);  
                    var message = new NdefMessage([textRecord]);  
                    var Ndef = plus.android.importClass('android.nfc.tech.Ndef');  
                    var NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable');  
                    var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
                    var ndef = Ndef.get(tag);  
                    if (ndef != null) {  
                        var size = message.toByteArray().length;  
                        console.log("size=" + size);  
                        ndef.connect();  
                        if (!ndef.isWritable()) {  
                            showToast("tag不允许写入");  
                            waiting.close();  
                            return ;  
                        }  
                        if (ndef.getMaxSize() < size) {  
                            showToast("文件大小超出容量");  
                            waiting.close();  
                            return ;  
                        }  

                        ndef.writeNdefMessage(message);  
                        waiting.close();  
                        showToast("写入数据成功.");  
                        return ;  
                    } else {  
                        var format = NdefFormatable.get(tag);  
                        if (format != null) {  
                            try {  
                                format.connect();  
                                format.format(message);  
                                showToast("格式化tag并且写入message");  
                                waiting.close();  
                                return ;  
                            } catch (e) {  
                                showToast("格式化tag失败.");  
                                waiting.close();  
                                return ;  
                            }  
                        } else {  
                            showToast("Tag不支持NDEF");  
                            waiting.close();  
                            return ;  
                        }  
                    }  
                }catch(e){  
                    console.log("error=" + e);  
                    waiting.close();  
                    alert('写入失败');  
                }  

            }  

            function __read(intent){  
                try{  
                    var content = "";  
                    waiting.setTitle('请勿移开标签\n正在读取数据...');  
                    var tag = plus.android.importClass("android.nfc.Tag");  
                    tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  
                    var bytesId  = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);  
                    console.log("bytesId:"+(bytesId));  
                    waiting.close();  
                    content +="卡片字节数组ID:"+tag.getId()+"<br/>";  
                    content +="卡片16进制ID:"+ bytesToHexString(tag.getId())+"<br/>";  
                    var tagid = reverseTwo(bytesToHexString(tag.getId()));  
                    content +="卡片16进制翻转ID:"+tagid+"<br/>";  
                    content +="卡片10进制卡号:"+parseInt(tagid, 16)+"<br/>";  

                    $("#content").html(content);  

                }catch(e){  
                    alert(e);  
                    //TODO handle the exception  
                }  
            }  

            function bytesToHexString(inarray){  
                var i, j, x;  
                var hex = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",  
                    "B", "C", "D", "E", "F" ];  
                var out = "";  
                for (j = 0; j < inarray.length; ++j) {  
                    x = parseInt(inarray[j]) & 0xff;  
                    i = (x >> 4) & 0x0f;  
                    out += hex[i];  
                    i = x & 0x0f;  
                    out += hex[i];  
                }  
                return out;  
            }  

            function reverseTwo(str)   
            {   

                var str1 = "";  
                for(var i = 1; i <= str.length; i++){  
                    str1 +=str[i-1];  
                    if(i%2==0){  
                        if(i == str.length){  
                            break;  
                        }  
                        str1+=":";  
                    }  
                }  
                var str2 = "";  
                for(var i = str1.split(":").length-1; i >= 0 ; i--){  
                    str2+= str1.split(":")[i];  
                }  
                return str2;  
            }  

            document.addEventListener('plusready',listenNFCStatus,false);  

            var waiting ;  
            var readyWriteData = false;  
            var readyRead = false;  
            function writeData(){  
                var textEle = document.getElementById('text');  
                if(!textEle.value){  
                    alert('请输入要写入的内容');  
                    return;  
                }  
                readyWriteData = true;  
                waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");  
            }  
            function readData(){  
                readyRead = true;  
                waiting = plus.nativeUI.showWaiting("请将NFC标签靠近!");  
            }  
        </script>  

        <style>  
            button{  
                width: 50%;  
                height: 50px;  
            }  
        </style>  
    </head>  
    <body>  
        输入要写入的内容:<br/><textarea id="text">姓名:张二蛋年龄:29地址:北京海淀区</textarea><br/>  
       <button onclick="writeData()">写入</button>  
        <button style="position: absolute; bottom: 100px; right: 100px;" onclick="readData()">读取</button><br/>  
        读取的内容:  
        <div id="content"/>  
    </body>  
</html>

manifest.json 模块权限配置勾选了NFC
避免打包之后刷卡会闪退

收起阅读 »

PDA终端扫描实现

扫码

以下方法都是非原生方式实现

Javascript获取扫码结果实现

document.onkeydown=function(e){  
    //webview不需要兼容ie  
    console.log(e.keyCode)  
}

该方法需要判断按键和间隔输入情况,用户可能在扫码的时候有其他按键等误操作,所以不建议用来进行获取扫码结果。

Native.js监听广播消息实现

参考论坛 回答

function plusReady() {   
    var main = plus.android.runtimeMainActivity();//获取activity  
    var context = plus.android.importClass('android.content.Context'); //上下文  
    var receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver',{  
    onReceive : doReceive });  
    var IntentFilter = plus.android.importClass('android.content.IntentFilter');  
    var Intent = plus.android.importClass('android.content.Intent');  
    var filter = new IntentFilter();  
    filter.addAction("com.zkc.scancode");//监听扫描  
    main.registerReceiver(receiver,filter);//注册监听  

    function doReceive(context, intent) {   
        plus.android.importClass(intent);//通过intent实例引入intent类,方便以后的‘.’操作  
        var Number = intent.getStringExtra("code");   
        console.log(Number);  
        main.unregisterReceiver(receiver);//取消监听  
    }  
}

销邦X8扫描枪

我这里使用的是销邦科技X8扫描设备,由于设备不一样导致文章中的代码不能直接使用,需要配置监听的数据才能连接。搜索销邦官网获取对应开发包下载

开发包截图

注意设置内勾选开启扫描,选择输入模式API:

PDA设置

打开开发说明查看参数:

pdf截图

代码对应修改如下:

···  

filter.addAction("com.android.server.scannerservice.broadcast");//监听扫描  

···  

intent.getStringExtra("scannerdata");//返回结果  

···

原代码实现的是扫码完成就取消监听这样不符合实际业务(多次扫描),但是不取消监听用同时有打开新的页面,这时会发现之前的页面还在监听扫描,当然在打开新页面的时候进行取消监听,但是当用户从新页面返回之前的页面时又需要重启监听,各种条件判断写出了比较麻烦。

这里采用的是接受扫描结果时判断是否是当前显示页面。首先在打开页面时把页面id存储到本地,并且重写back:

function pageInit(){  
    var _self = plus.webview.currentWebview()  
    localStorage.setItem('WEBVIEW_ID', _self.id)  
    mui.back = function() {  
        localStorage.setItem('WEBVIEW_ID', _self.opener().id)  
        _self.close()  
    }  
}

然后判断页面id:

function scan(callback){  
    var main = plus.android.runtimeMainActivity(); //获取activity  
    var receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {  
        onReceive: function(context, intent){//实现onReceiver回调函数  
            if(plus.webview.currentWebview().id != localStorage.getItem(util.config.WEBVIEW_ID)) return  
            callback(intent.getStringExtra('scannerdata'))  
        }   
    });  
    var IntentFilter = plus.android.importClass('android.content.IntentFilter');//引入过滤器  
    var Intent = plus.android.importClass('android.content.Intent');  
    var filter = new IntentFilter();  
    filter.addAction('com.android.server.scannerservice.broadcast'); //监听扫码广播  
    main.registerReceiver(receiver, filter); //注册监听  
}

页面使用:

mui.plusReady(function () {  
    pageInit()  
    setTimeout(function(){  
        scan(function(code){  
            console.log('扫描结果:'+code)  
        })  
    },300)  
})

注意:在HBuilder控制台没有调试信息,需要在webview调试窗口中才能看到打印信息。另建议在plusReady中延迟执行scan()。

霍尼韦尔扫描枪

首先需要在设备上去设置监听的对象名(我这里设置成和销邦设备一样的com.android.server.scannerservice.broadcast),接受参数的时候再判断一下设备plus.device.model进行切换接受返回结果的对象名:

scan: function(callback){  
    var main = plus.android.runtimeMainActivity(); //获取activity  
    var context = plus.android.importClass('android.content.Context'); //上下文  
    var receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {  
        onReceive: function(context, intent){//实现onReceiver回调函数  
        if(plus.webview.currentWebview().id != localStorage.getItem(util.config.WEBVIEW_ID)) return  
            var _key = plus.device.model == 'EDA50K' ? 'data' : 'scannerdata';  
            callback(intent.getStringExtra(_key))  
        }  
    });  
    var IntentFilter = plus.android.importClass('android.content.IntentFilter');//引入过滤器  
    var Intent = plus.android.importClass('android.content.Intent');  
    var filter = new IntentFilter();  
    filter.addAction('com.android.server.scannerservice.broadcast'); //监听扫码广播  
    main.registerReceiver(receiver, filter); //注册监听  
}
继续阅读 »

以下方法都是非原生方式实现

Javascript获取扫码结果实现

document.onkeydown=function(e){  
    //webview不需要兼容ie  
    console.log(e.keyCode)  
}

该方法需要判断按键和间隔输入情况,用户可能在扫码的时候有其他按键等误操作,所以不建议用来进行获取扫码结果。

Native.js监听广播消息实现

参考论坛 回答

function plusReady() {   
    var main = plus.android.runtimeMainActivity();//获取activity  
    var context = plus.android.importClass('android.content.Context'); //上下文  
    var receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver',{  
    onReceive : doReceive });  
    var IntentFilter = plus.android.importClass('android.content.IntentFilter');  
    var Intent = plus.android.importClass('android.content.Intent');  
    var filter = new IntentFilter();  
    filter.addAction("com.zkc.scancode");//监听扫描  
    main.registerReceiver(receiver,filter);//注册监听  

    function doReceive(context, intent) {   
        plus.android.importClass(intent);//通过intent实例引入intent类,方便以后的‘.’操作  
        var Number = intent.getStringExtra("code");   
        console.log(Number);  
        main.unregisterReceiver(receiver);//取消监听  
    }  
}

销邦X8扫描枪

我这里使用的是销邦科技X8扫描设备,由于设备不一样导致文章中的代码不能直接使用,需要配置监听的数据才能连接。搜索销邦官网获取对应开发包下载

开发包截图

注意设置内勾选开启扫描,选择输入模式API:

PDA设置

打开开发说明查看参数:

pdf截图

代码对应修改如下:

···  

filter.addAction("com.android.server.scannerservice.broadcast");//监听扫描  

···  

intent.getStringExtra("scannerdata");//返回结果  

···

原代码实现的是扫码完成就取消监听这样不符合实际业务(多次扫描),但是不取消监听用同时有打开新的页面,这时会发现之前的页面还在监听扫描,当然在打开新页面的时候进行取消监听,但是当用户从新页面返回之前的页面时又需要重启监听,各种条件判断写出了比较麻烦。

这里采用的是接受扫描结果时判断是否是当前显示页面。首先在打开页面时把页面id存储到本地,并且重写back:

function pageInit(){  
    var _self = plus.webview.currentWebview()  
    localStorage.setItem('WEBVIEW_ID', _self.id)  
    mui.back = function() {  
        localStorage.setItem('WEBVIEW_ID', _self.opener().id)  
        _self.close()  
    }  
}

然后判断页面id:

function scan(callback){  
    var main = plus.android.runtimeMainActivity(); //获取activity  
    var receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {  
        onReceive: function(context, intent){//实现onReceiver回调函数  
            if(plus.webview.currentWebview().id != localStorage.getItem(util.config.WEBVIEW_ID)) return  
            callback(intent.getStringExtra('scannerdata'))  
        }   
    });  
    var IntentFilter = plus.android.importClass('android.content.IntentFilter');//引入过滤器  
    var Intent = plus.android.importClass('android.content.Intent');  
    var filter = new IntentFilter();  
    filter.addAction('com.android.server.scannerservice.broadcast'); //监听扫码广播  
    main.registerReceiver(receiver, filter); //注册监听  
}

页面使用:

mui.plusReady(function () {  
    pageInit()  
    setTimeout(function(){  
        scan(function(code){  
            console.log('扫描结果:'+code)  
        })  
    },300)  
})

注意:在HBuilder控制台没有调试信息,需要在webview调试窗口中才能看到打印信息。另建议在plusReady中延迟执行scan()。

霍尼韦尔扫描枪

首先需要在设备上去设置监听的对象名(我这里设置成和销邦设备一样的com.android.server.scannerservice.broadcast),接受参数的时候再判断一下设备plus.device.model进行切换接受返回结果的对象名:

scan: function(callback){  
    var main = plus.android.runtimeMainActivity(); //获取activity  
    var context = plus.android.importClass('android.content.Context'); //上下文  
    var receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {  
        onReceive: function(context, intent){//实现onReceiver回调函数  
        if(plus.webview.currentWebview().id != localStorage.getItem(util.config.WEBVIEW_ID)) return  
            var _key = plus.device.model == 'EDA50K' ? 'data' : 'scannerdata';  
            callback(intent.getStringExtra(_key))  
        }  
    });  
    var IntentFilter = plus.android.importClass('android.content.IntentFilter');//引入过滤器  
    var Intent = plus.android.importClass('android.content.Intent');  
    var filter = new IntentFilter();  
    filter.addAction('com.android.server.scannerservice.broadcast'); //监听扫码广播  
    main.registerReceiver(receiver, filter); //注册监听  
}
收起阅读 »

快递连续扫码

<!DOCTYPE html>
<html>

<head>  
    <meta charset="utf-8">  
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
    <title></title>  
    <link href="../css/mui.min.css" rel="stylesheet" />  
    <link href="../css/iconfont.css" rel="stylesheet" />  
    <link href="../css/common.css" rel="stylesheet" />  
    <link href="../css/style.css" rel="stylesheet" />  
    <script src="../js/mui.min.js"></script>  
    <script src="../js/public.js"></script>  
    <style>  
        #bcid {  
            height: 280px;  
            width:300px;  
        }  
    </style>  
</head>  

<body>  
    <div class="scan-img-div" style="display: none;">  
        <div  id="bcid" >  
        </div>  
    </div>  

    <div class="padding-lr20">  
        <div class="scan-result-div">  
            <div class="wxrow">  
                <div class='wxcenter padding-l5 width60 size12 bold'>下一站:</div>  
                <div class='flex1 relative'>  
                    <select class="mui-btn send-select">  
                        <option>请选择下一站</option>  
                        <option value="item-1">item-1</option>  
                        <option value="item-2">item-2</option>  
                        <option value="item-3">item-3</option>  
                        <option value="item-4">item-4</option>  
                        <option value="item-5">item-5</option>  
                    </select>  
                    <span class="iconfont icon-xiajiantou po-down"></span>  
                </div>  
            </div>  
            <div class="wxrow padding-lr5 padding-b10 margin-b10 margin-t30 bor-b-g2 size12">  
                <div class="flex1 bold">扫描结果</div>  
                <div class="">  
                    <span class="b-999">票数:</span>  
                    <span class="g-009999">8xx</span>  
                </div>  
            </div>  
            <div class="wxrow margin-t10 padding-lr10">  
                <div class="b-333 margin-r15">589078476897438xxx</div>  
                <div class="width40 wxaround">  
                    <span class="iconfont icon-cha r-ff0000"></span>  
                </div>  
            </div>  
            <div class="wxrow margin-t10 padding-lr10">  
                <div class="b-333 margin-r15">589078476897438xxx</div>  
                <div class="width40 wxaround margin-l40">  
                    <span class="iconfont icon-cha r-ff0000"></span>  
                </div>  
            </div>  

        </div>  
    </div>  

    <div class="fix-b-scan wxrow">  
        <div class="flex1 scan-btn bg-o-ff6600" id="scan-go">确认出仓</div>  
        <div class="flex2 scan-btn bg-b-383838" onclick="openScan()">扫描</div>  
    </div>  
    <script type="text/javascript">  
        console.log(1)  
        mui.init()  
        let scan = null;  
        function openScan() {  
            ddsd.qs('.scan-img-div').style.display = 'block'  
            scan = new plus.barcode.Barcode('bcid', [  
                plus.barcode.EAN13,  
                plus.barcode.EAN8,  
                plus.barcode.CODE39,  
                plus.barcode.CODE93,  
                plus.barcode.CODE128  
            ], {  
                top:'1000px',  
                left:'0px',  
                width: '100%',  
                height: '100px',  
                position: 'static',  
                frameColor: '#00FF00',  
                scanbarColor: '#00FF00'  
            });  
            scan.onmarked = onmarked;  
            scan.start();  
        }  
        mui.plusReady(function() {  

            function onmarked(type, result) {  

                var text = '未知: ';  
                switch(type) {  
                    case plus.barcode.QR:  
                        text = 'QR: ';  
                        break;  
                    case plus.barcode.EAN13:  
                        text = 'EAN13: ';  
                        break;  
                    case plus.barcode.EAN8:  
                        text = 'EAN8: ';  
                        break;  
                    case plus.barcode.CODE39:  
                        text = 'CODE39: ';  
                        break;  
                    case plus.barcode.CODE93:  
                        text = 'CODE93: ';  
                        break;  
                    case plus.barcode.CODE128:  
                        text = 'CODE128: ';  
                        break;  
                }  
                                console.log(text + result);  

                if(result) {  
                    console.log(result)  

// scan.close();
// window.location.reload();
scan.cancel();
setTimeout(() => {
scan.start();
},1000)

                }  
            }  

            mui("body").on('tap', '#scan-go', function() {  
                mui.openWindow({  
                    url: 'scan_success.html',  
                    id: 'scan_success.html',  
                    styles: { // 窗口参数 参考5+规范中的WebviewStyle,也就是说WebviewStyle下的参数都可以在此设置  
                        titleNView: { // 窗口的标题栏控件  
                            autoBackButton: true,  
                            titleText: '出仓成功', // 标题栏文字,当不设置此属性时,默认加载当前页面的标题,并自动更新页面的标题  
                            titleColor: "#000000", // 字体颜色,颜色值格式为"#RRGGBB",默认值为"#000000"  
                            titleSize: "17px", // 字体大小,默认17px  
                            backgroundColor: "#FFCC00", // 控件背景颜色,颜色值格式为"#RRGGBB",默认值为"#F7F7F7"  
                        }  
                    }  
                });  
            })  
        })  
    </script>  

</body>  

</html>

继续阅读 »

<!DOCTYPE html>
<html>

<head>  
    <meta charset="utf-8">  
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
    <title></title>  
    <link href="../css/mui.min.css" rel="stylesheet" />  
    <link href="../css/iconfont.css" rel="stylesheet" />  
    <link href="../css/common.css" rel="stylesheet" />  
    <link href="../css/style.css" rel="stylesheet" />  
    <script src="../js/mui.min.js"></script>  
    <script src="../js/public.js"></script>  
    <style>  
        #bcid {  
            height: 280px;  
            width:300px;  
        }  
    </style>  
</head>  

<body>  
    <div class="scan-img-div" style="display: none;">  
        <div  id="bcid" >  
        </div>  
    </div>  

    <div class="padding-lr20">  
        <div class="scan-result-div">  
            <div class="wxrow">  
                <div class='wxcenter padding-l5 width60 size12 bold'>下一站:</div>  
                <div class='flex1 relative'>  
                    <select class="mui-btn send-select">  
                        <option>请选择下一站</option>  
                        <option value="item-1">item-1</option>  
                        <option value="item-2">item-2</option>  
                        <option value="item-3">item-3</option>  
                        <option value="item-4">item-4</option>  
                        <option value="item-5">item-5</option>  
                    </select>  
                    <span class="iconfont icon-xiajiantou po-down"></span>  
                </div>  
            </div>  
            <div class="wxrow padding-lr5 padding-b10 margin-b10 margin-t30 bor-b-g2 size12">  
                <div class="flex1 bold">扫描结果</div>  
                <div class="">  
                    <span class="b-999">票数:</span>  
                    <span class="g-009999">8xx</span>  
                </div>  
            </div>  
            <div class="wxrow margin-t10 padding-lr10">  
                <div class="b-333 margin-r15">589078476897438xxx</div>  
                <div class="width40 wxaround">  
                    <span class="iconfont icon-cha r-ff0000"></span>  
                </div>  
            </div>  
            <div class="wxrow margin-t10 padding-lr10">  
                <div class="b-333 margin-r15">589078476897438xxx</div>  
                <div class="width40 wxaround margin-l40">  
                    <span class="iconfont icon-cha r-ff0000"></span>  
                </div>  
            </div>  

        </div>  
    </div>  

    <div class="fix-b-scan wxrow">  
        <div class="flex1 scan-btn bg-o-ff6600" id="scan-go">确认出仓</div>  
        <div class="flex2 scan-btn bg-b-383838" onclick="openScan()">扫描</div>  
    </div>  
    <script type="text/javascript">  
        console.log(1)  
        mui.init()  
        let scan = null;  
        function openScan() {  
            ddsd.qs('.scan-img-div').style.display = 'block'  
            scan = new plus.barcode.Barcode('bcid', [  
                plus.barcode.EAN13,  
                plus.barcode.EAN8,  
                plus.barcode.CODE39,  
                plus.barcode.CODE93,  
                plus.barcode.CODE128  
            ], {  
                top:'1000px',  
                left:'0px',  
                width: '100%',  
                height: '100px',  
                position: 'static',  
                frameColor: '#00FF00',  
                scanbarColor: '#00FF00'  
            });  
            scan.onmarked = onmarked;  
            scan.start();  
        }  
        mui.plusReady(function() {  

            function onmarked(type, result) {  

                var text = '未知: ';  
                switch(type) {  
                    case plus.barcode.QR:  
                        text = 'QR: ';  
                        break;  
                    case plus.barcode.EAN13:  
                        text = 'EAN13: ';  
                        break;  
                    case plus.barcode.EAN8:  
                        text = 'EAN8: ';  
                        break;  
                    case plus.barcode.CODE39:  
                        text = 'CODE39: ';  
                        break;  
                    case plus.barcode.CODE93:  
                        text = 'CODE93: ';  
                        break;  
                    case plus.barcode.CODE128:  
                        text = 'CODE128: ';  
                        break;  
                }  
                                console.log(text + result);  

                if(result) {  
                    console.log(result)  

// scan.close();
// window.location.reload();
scan.cancel();
setTimeout(() => {
scan.start();
},1000)

                }  
            }  

            mui("body").on('tap', '#scan-go', function() {  
                mui.openWindow({  
                    url: 'scan_success.html',  
                    id: 'scan_success.html',  
                    styles: { // 窗口参数 参考5+规范中的WebviewStyle,也就是说WebviewStyle下的参数都可以在此设置  
                        titleNView: { // 窗口的标题栏控件  
                            autoBackButton: true,  
                            titleText: '出仓成功', // 标题栏文字,当不设置此属性时,默认加载当前页面的标题,并自动更新页面的标题  
                            titleColor: "#000000", // 字体颜色,颜色值格式为"#RRGGBB",默认值为"#000000"  
                            titleSize: "17px", // 字体大小,默认17px  
                            backgroundColor: "#FFCC00", // 控件背景颜色,颜色值格式为"#RRGGBB",默认值为"#F7F7F7"  
                        }  
                    }  
                });  
            })  
        })  
    </script>  

</body>  

</html>

收起阅读 »

5+App升级iOS12系统后应用可能崩溃的解决方案

iOS12

部分开发者反馈app在iOS12上会崩溃,而同样代码在iOS12以下的手机正常。但也并非所有代码写法都会引发崩溃。
苹果最新的策略在iOS12及以后系统将不再维护UIWebview内核,都推荐改为WKWebview。
目前5+App、wap2app打包时,默认是UIWebview。uni-app默认是WKWebview。
所以5+App、wap2app的开发者,如果遇到iOS12的兼容问题,有如下方案:

1. 将app的iOS webview内核更改为WKWebview

在manifest.json的plus->kernel->ios节点中配置默认使用WKWebviwe内核:

//...  
"plus": {  
        "kernel": {  
            "ios": "WKWebview"  
        },  
        //...  
}

注意:

  1. 目前使用WKWebview内核不支持“启用js原生混淆”功能,云端打包iOS时不要勾选此项配置。
  2. wgt资源加密要注意,iOS一旦使用WKWebview也不支持解压加密的wgt资源。
  3. WKWebview里HTML5的存储如cookie、localstorage等和UIWebview不互通,应用升级后,手机端老的cookie等数据拿不到了。
  4. WKWebview不支持overrideresource。

2. 优化代码写法,避免崩溃

如果代码里有容易引发内存占用且没有回收的代码,比如不停运行的计时器,在UIWebview下更容易崩溃。
在js里不停大范围修改整体dom引发不停重布局,也容易崩溃。

如果配置为WKWebviw内核还存在闪退问题,请提供出现问题的ipa,并详细说明操作出现闪退的步骤。

另,由于一个三方库和iOS12的模拟器冲突了,HBuilde早期版本在真机运行到iOS12模拟器会无法启动,请升级到最新版。此问题不影响真机。

继续阅读 »

部分开发者反馈app在iOS12上会崩溃,而同样代码在iOS12以下的手机正常。但也并非所有代码写法都会引发崩溃。
苹果最新的策略在iOS12及以后系统将不再维护UIWebview内核,都推荐改为WKWebview。
目前5+App、wap2app打包时,默认是UIWebview。uni-app默认是WKWebview。
所以5+App、wap2app的开发者,如果遇到iOS12的兼容问题,有如下方案:

1. 将app的iOS webview内核更改为WKWebview

在manifest.json的plus->kernel->ios节点中配置默认使用WKWebviwe内核:

//...  
"plus": {  
        "kernel": {  
            "ios": "WKWebview"  
        },  
        //...  
}

注意:

  1. 目前使用WKWebview内核不支持“启用js原生混淆”功能,云端打包iOS时不要勾选此项配置。
  2. wgt资源加密要注意,iOS一旦使用WKWebview也不支持解压加密的wgt资源。
  3. WKWebview里HTML5的存储如cookie、localstorage等和UIWebview不互通,应用升级后,手机端老的cookie等数据拿不到了。
  4. WKWebview不支持overrideresource。

2. 优化代码写法,避免崩溃

如果代码里有容易引发内存占用且没有回收的代码,比如不停运行的计时器,在UIWebview下更容易崩溃。
在js里不停大范围修改整体dom引发不停重布局,也容易崩溃。

如果配置为WKWebviw内核还存在闪退问题,请提供出现问题的ipa,并详细说明操作出现闪退的步骤。

另,由于一个三方库和iOS12的模拟器冲突了,HBuilde早期版本在真机运行到iOS12模拟器会无法启动,请升级到最新版。此问题不影响真机。

收起阅读 »

uni-app 中清除定时器

切换页面 uniapp

无论是获取短信码,还是在活动页轮询获取当前活动最新信息,都需要用到定时器。
但是,定时器如果不及时合理地清除,会造成业务逻辑混乱甚至应用卡死的情况。

uni-app 中在某个页面中启动定时器后,一定要在页面关闭时将定时器清除掉。即在页面卸载(关闭)的生命周期函数里,清除定时器。

onUnload:function(){  
    if(this.timer) {  
        clearInterval(this.timer);  
        this.timer = null;  
    }  
}

附件中提供了简单的 demo,下载后直接在 HBuilderX 中运行即可。

继续阅读 »

无论是获取短信码,还是在活动页轮询获取当前活动最新信息,都需要用到定时器。
但是,定时器如果不及时合理地清除,会造成业务逻辑混乱甚至应用卡死的情况。

uni-app 中在某个页面中启动定时器后,一定要在页面关闭时将定时器清除掉。即在页面卸载(关闭)的生命周期函数里,清除定时器。

onUnload:function(){  
    if(this.timer) {  
        clearInterval(this.timer);  
        this.timer = null;  
    }  
}

附件中提供了简单的 demo,下载后直接在 HBuilderX 中运行即可。

收起阅读 »

android开发之仿商城首页Banner图的实现

  实现效果:当banner滚动的时候 首先会缩放当前以及上一个或下一个banner图,当banner滚动时会,背景会随滚动系数变化缩放(自动滚动),下面相关技术人员来分享一下源码:
//0无状态,1缩放,2放大,3不能再播放动画

private int status = 0;

private void fada() {

if (status == 0 || status == 1) {

AnimatorSet animatorSetsuofang = new AnimatorSet();//组合动画

ObjectAnimator scaleX = ObjectAnimator.ofFloat(viewPager, "scaleX", 0.9f, 1f);

ObjectAnimator scaleY = ObjectAnimator.ofFloat(viewPager, "scaleY", 0.9f, 1f);

animatorSetsuofang.setDuration(500);

animatorSetsuofang.setInterpolator(new LinearInterpolator());

animatorSetsuofang.play(scaleX).with(scaleY);//两个动画同时开始

animatorSetsuofang.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationStart(Animator animation) {

super.onAnimationStart(animation);

setViewPagerIsScroll(false);

stopAutoPlay();

status = 3;

}

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

setViewPagerIsScroll(true);

Log.e("as", "sa");

startAutoPlay();

status = 2;

}

});

animatorSetsuofang.start();

}

}

private void suoxia() {

if (status == 0 || status == 2) {

AnimatorSet animatorSetsuofang = new AnimatorSet();//组合动画

ObjectAnimator scaleX = ObjectAnimator.ofFloat(viewPager, "scaleX", 1f, 0.9f);

ObjectAnimator scaleY = ObjectAnimator.ofFloat(viewPager, "scaleY", 1f, 0.9f);

animatorSetsuofang.setDuration(200);

animatorSetsuofang.setInterpolator(new LinearInterpolator());

animatorSetsuofang.play(scaleX).with(scaleY);//两个动画同时开始

animatorSetsuofang.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationStart(Animator animation) {

super.onAnimationStart(animation);

setViewPagerIsScroll(false);

stopAutoPlay();

status = 3;

}

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

setViewPagerIsScroll(true);

// startAutoPlay();

status = 1;

}

});

animatorSetsuofang.start();

}

}

动画联动效果实现:

private final Runnable task = new Runnable() {

@Override

public void run() {

if (status == 0 || status == 2) {

AnimatorSet animatorSetsuofang = new AnimatorSet();//组合动画

ObjectAnimator scaleX = ObjectAnimator.ofFloat(viewPager, "scaleX", 1f, 0.9f);

ObjectAnimator scaleY = ObjectAnimator.ofFloat(viewPager, "scaleY", 1f, 0.9f);

animatorSetsuofang.setDuration(300);

animatorSetsuofang.setInterpolator(new LinearInterpolator());

animatorSetsuofang.play(scaleX).with(scaleY);//两个动画同时开始

animatorSetsuofang.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationStart(Animator animation) {

super.onAnimationStart(animation);

setViewPagerIsScroll(false);

status = 3;

}

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

setViewPagerIsScroll(true);

if (count > 1 && isAutoPlay) {

currentItem = currentItem % (count + 1) + 1;

// Log.i(tag, "curr:" + currentItem + " count:" + count);

if (currentItem == 1) {

viewPager.setCurrentItem(currentItem, false);

handler.post(task);

} else {

viewPager.setCurrentItem(currentItem);

handler.postDelayed(task, delayTime);

}

}

status = 1;

}

});

animatorSetsuofang.start();

}

}

};

缩放(拖动)效果实现:

@Override

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

int num = 0;

if (mOnPageChangeListener != null) {

// Log.e("as", "position" + position + " ----positionOffset " + positionOffset + " positionOffsetPixels" + positionOffsetPixels);

// Log.e(scale);

Log.e("as", imageUrls.size() + "" + " currentItem" + currentItem);

if (positionOffset > 0) {

Log.e("as", "position" + position + " currentItem" + currentItem + "mViewPagerIndex" + mViewPagerIndex);

// Log.e("as", mViewPagerIndex + "");

if (touch) {

if (currentItem == imageUrls.size() + 1) {

Glide.with(context).load(imageUrls.get(0)).into(roundImageView);

Glide.with(context).load(imageUrls.get(0)).into(roundImagetwo);

} else {

if (currentItem == 0) {

Glide.with(context).load(imageUrls.get(imageUrls.size() - 1)).into(roundImageView);

Glide.with(context).load(imageUrls.get(imageUrls.size() - 1)).into(roundImagetwo);

} else {

Glide.with(context).load(imageUrls.get(currentItem - 1)).into(roundImageView);

Glide.with(context).load(imageUrls.get(currentItem - 1)).into(roundImagetwo);

}

}

if (position == mViewPagerIndex) {

Log.e("tt", "左");

if (position == imageUrls.size()) {

num = 0;

} else {

num = position;

}

Glide.with(context).load(imageUrls.get(num)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

roundImageView.setVisibility(VISIBLE);

roundImagetwo.setVisibility(INVISIBLE);

} else {

Log.e("tt", "右");

if (position == 0) {

num = imageUrls.size();

} else {

num = position;

}

Glide.with(context).load(imageUrls.get(num - 1)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

roundImagetwo.setVisibility(VISIBLE);

roundImageView.setVisibility(INVISIBLE);

}

} else {

if (!touchover) {

if (position < currentItem) {

roundImageView.setVisibility(VISIBLE);

roundImagetwo.setVisibility(INVISIBLE);

}

}

if (position == imageUrls.size()) {

Glide.with(context).load(imageUrls.get(0)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

} else if (position == 0) {

num = imageUrls.size();

Glide.with(context).load(imageUrls.get(num - 1)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

} else {

if (position == mViewPagerIndex) {

Glide.with(context).load(imageUrls.get(position)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

} else {

if (!touchover) {

Glide.with(context).load(imageUrls.get(position)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

} else {

Glide.with(context).load(imageUrls.get(position - 1)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

roundImageView.setVisibility(INVISIBLE);

roundImagetwo.setVisibility(VISIBLE);

}

//

}

}

}

//

} else {

roundImagetwo.setVisibility(VISIBLE);

roundImageView.setVisibility(VISIBLE);

if (currentItem == imageUrls.size() + 1) {

Glide.with(context).load(imageUrls.get(0)).into(roundImageView);

Glide.with(context).load(imageUrls.get(0)).into(roundImagetwo);

} else {

if (currentItem == 0) {

Glide.with(context).load(imageUrls.get(imageUrls.size() - 1)).into(roundImageView);

Glide.with(context).load(imageUrls.get(imageUrls.size() - 1)).into(roundImagetwo);

} else {

Glide.with(context).load(imageUrls.get(currentItem - 1)).into(roundImageView);

Glide.with(context).load(imageUrls.get(currentItem - 1)).into(roundImagetwo);

}

}

}

roundImagetwo.setRound(1f - positionOffset);

roundImageView.setRound(positionOffset);

if ((positionOffset == 0) && touch == false) {

fada();

}

mOnPageChangeListener.onPageScrolled(toRealPosition(position), positionOffset, positionOffsetPixels);

}

}

轮播图数据绑定

banner.setImages(imagebgUrls)

.setImageLoader(new GlideImageLoader())

.setImageList(images)

.start();

  好了,到这里就算是完后才能了,如果大家需要改banner依赖包的setImageList()方法,不然无法在主线程中添加数据,还存在不理解的地方也是可以留言咨询。
  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

继续阅读 »

  实现效果:当banner滚动的时候 首先会缩放当前以及上一个或下一个banner图,当banner滚动时会,背景会随滚动系数变化缩放(自动滚动),下面相关技术人员来分享一下源码:
//0无状态,1缩放,2放大,3不能再播放动画

private int status = 0;

private void fada() {

if (status == 0 || status == 1) {

AnimatorSet animatorSetsuofang = new AnimatorSet();//组合动画

ObjectAnimator scaleX = ObjectAnimator.ofFloat(viewPager, "scaleX", 0.9f, 1f);

ObjectAnimator scaleY = ObjectAnimator.ofFloat(viewPager, "scaleY", 0.9f, 1f);

animatorSetsuofang.setDuration(500);

animatorSetsuofang.setInterpolator(new LinearInterpolator());

animatorSetsuofang.play(scaleX).with(scaleY);//两个动画同时开始

animatorSetsuofang.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationStart(Animator animation) {

super.onAnimationStart(animation);

setViewPagerIsScroll(false);

stopAutoPlay();

status = 3;

}

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

setViewPagerIsScroll(true);

Log.e("as", "sa");

startAutoPlay();

status = 2;

}

});

animatorSetsuofang.start();

}

}

private void suoxia() {

if (status == 0 || status == 2) {

AnimatorSet animatorSetsuofang = new AnimatorSet();//组合动画

ObjectAnimator scaleX = ObjectAnimator.ofFloat(viewPager, "scaleX", 1f, 0.9f);

ObjectAnimator scaleY = ObjectAnimator.ofFloat(viewPager, "scaleY", 1f, 0.9f);

animatorSetsuofang.setDuration(200);

animatorSetsuofang.setInterpolator(new LinearInterpolator());

animatorSetsuofang.play(scaleX).with(scaleY);//两个动画同时开始

animatorSetsuofang.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationStart(Animator animation) {

super.onAnimationStart(animation);

setViewPagerIsScroll(false);

stopAutoPlay();

status = 3;

}

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

setViewPagerIsScroll(true);

// startAutoPlay();

status = 1;

}

});

animatorSetsuofang.start();

}

}

动画联动效果实现:

private final Runnable task = new Runnable() {

@Override

public void run() {

if (status == 0 || status == 2) {

AnimatorSet animatorSetsuofang = new AnimatorSet();//组合动画

ObjectAnimator scaleX = ObjectAnimator.ofFloat(viewPager, "scaleX", 1f, 0.9f);

ObjectAnimator scaleY = ObjectAnimator.ofFloat(viewPager, "scaleY", 1f, 0.9f);

animatorSetsuofang.setDuration(300);

animatorSetsuofang.setInterpolator(new LinearInterpolator());

animatorSetsuofang.play(scaleX).with(scaleY);//两个动画同时开始

animatorSetsuofang.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationStart(Animator animation) {

super.onAnimationStart(animation);

setViewPagerIsScroll(false);

status = 3;

}

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

setViewPagerIsScroll(true);

if (count > 1 && isAutoPlay) {

currentItem = currentItem % (count + 1) + 1;

// Log.i(tag, "curr:" + currentItem + " count:" + count);

if (currentItem == 1) {

viewPager.setCurrentItem(currentItem, false);

handler.post(task);

} else {

viewPager.setCurrentItem(currentItem);

handler.postDelayed(task, delayTime);

}

}

status = 1;

}

});

animatorSetsuofang.start();

}

}

};

缩放(拖动)效果实现:

@Override

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

int num = 0;

if (mOnPageChangeListener != null) {

// Log.e("as", "position" + position + " ----positionOffset " + positionOffset + " positionOffsetPixels" + positionOffsetPixels);

// Log.e(scale);

Log.e("as", imageUrls.size() + "" + " currentItem" + currentItem);

if (positionOffset > 0) {

Log.e("as", "position" + position + " currentItem" + currentItem + "mViewPagerIndex" + mViewPagerIndex);

// Log.e("as", mViewPagerIndex + "");

if (touch) {

if (currentItem == imageUrls.size() + 1) {

Glide.with(context).load(imageUrls.get(0)).into(roundImageView);

Glide.with(context).load(imageUrls.get(0)).into(roundImagetwo);

} else {

if (currentItem == 0) {

Glide.with(context).load(imageUrls.get(imageUrls.size() - 1)).into(roundImageView);

Glide.with(context).load(imageUrls.get(imageUrls.size() - 1)).into(roundImagetwo);

} else {

Glide.with(context).load(imageUrls.get(currentItem - 1)).into(roundImageView);

Glide.with(context).load(imageUrls.get(currentItem - 1)).into(roundImagetwo);

}

}

if (position == mViewPagerIndex) {

Log.e("tt", "左");

if (position == imageUrls.size()) {

num = 0;

} else {

num = position;

}

Glide.with(context).load(imageUrls.get(num)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

roundImageView.setVisibility(VISIBLE);

roundImagetwo.setVisibility(INVISIBLE);

} else {

Log.e("tt", "右");

if (position == 0) {

num = imageUrls.size();

} else {

num = position;

}

Glide.with(context).load(imageUrls.get(num - 1)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

roundImagetwo.setVisibility(VISIBLE);

roundImageView.setVisibility(INVISIBLE);

}

} else {

if (!touchover) {

if (position < currentItem) {

roundImageView.setVisibility(VISIBLE);

roundImagetwo.setVisibility(INVISIBLE);

}

}

if (position == imageUrls.size()) {

Glide.with(context).load(imageUrls.get(0)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

} else if (position == 0) {

num = imageUrls.size();

Glide.with(context).load(imageUrls.get(num - 1)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

} else {

if (position == mViewPagerIndex) {

Glide.with(context).load(imageUrls.get(position)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

} else {

if (!touchover) {

Glide.with(context).load(imageUrls.get(position)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

} else {

Glide.with(context).load(imageUrls.get(position - 1)).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImagebg);

roundImageView.setVisibility(INVISIBLE);

roundImagetwo.setVisibility(VISIBLE);

}

//

}

}

}

//

} else {

roundImagetwo.setVisibility(VISIBLE);

roundImageView.setVisibility(VISIBLE);

if (currentItem == imageUrls.size() + 1) {

Glide.with(context).load(imageUrls.get(0)).into(roundImageView);

Glide.with(context).load(imageUrls.get(0)).into(roundImagetwo);

} else {

if (currentItem == 0) {

Glide.with(context).load(imageUrls.get(imageUrls.size() - 1)).into(roundImageView);

Glide.with(context).load(imageUrls.get(imageUrls.size() - 1)).into(roundImagetwo);

} else {

Glide.with(context).load(imageUrls.get(currentItem - 1)).into(roundImageView);

Glide.with(context).load(imageUrls.get(currentItem - 1)).into(roundImagetwo);

}

}

}

roundImagetwo.setRound(1f - positionOffset);

roundImageView.setRound(positionOffset);

if ((positionOffset == 0) && touch == false) {

fada();

}

mOnPageChangeListener.onPageScrolled(toRealPosition(position), positionOffset, positionOffsetPixels);

}

}

轮播图数据绑定

banner.setImages(imagebgUrls)

.setImageLoader(new GlideImageLoader())

.setImageList(images)

.start();

  好了,到这里就算是完后才能了,如果大家需要改banner依赖包的setImageList()方法,不然无法在主线程中添加数据,还存在不理解的地方也是可以留言咨询。
  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

收起阅读 »

使用uni.navigateBack修改上一个页面值,多页面传参通信解决方案

uniapp

此类需求大概意思是:A页面进入B页面,B页面返回并传值给A。

var pages = getCurrentPages();
var currPage = pages[pages.length - 1]; //当前页面
var prevPage = pages[pages.length - 2]; //上一个页面

//直接调用上一个页面的setData()方法,把数据存到上一个页面中去
prevPage.setData({
mdata:1
})
uni.navigateBack(); //上一个页面数据无法修改

解决方案:onfire.js 是一个很简单的事件分发的Javascript库(仅仅 0.9kb),简洁实用。github地址:https://github.com/hustcc/onfire.js/blob/master/README_zh.md
可以用于:

  1. 简单的事件分发;
  2. 在 react / vue.js / angular 用于跨组件的轻量级实现;
  3. 事件订阅和发布;
    A页面:
    onShow:function(){
    var that = this;
    onfire.on('setAddressInfo',function(addressInfo){
    that.addressInfo = addressInfo;
    })
    },
    B页面:
    selectText: function(e){
    var that = this;
    var that_addressInfo ={
    location: e.currentTarget.id
    }
    onfire.fire('setAddressInfo',that_addressInfo);
    uni.navigateBack();
    }

参考来源:https://juejin.im/post/5907f120b123db3ee48d2a4f

继续阅读 »

此类需求大概意思是:A页面进入B页面,B页面返回并传值给A。

var pages = getCurrentPages();
var currPage = pages[pages.length - 1]; //当前页面
var prevPage = pages[pages.length - 2]; //上一个页面

//直接调用上一个页面的setData()方法,把数据存到上一个页面中去
prevPage.setData({
mdata:1
})
uni.navigateBack(); //上一个页面数据无法修改

解决方案:onfire.js 是一个很简单的事件分发的Javascript库(仅仅 0.9kb),简洁实用。github地址:https://github.com/hustcc/onfire.js/blob/master/README_zh.md
可以用于:

  1. 简单的事件分发;
  2. 在 react / vue.js / angular 用于跨组件的轻量级实现;
  3. 事件订阅和发布;
    A页面:
    onShow:function(){
    var that = this;
    onfire.on('setAddressInfo',function(addressInfo){
    that.addressInfo = addressInfo;
    })
    },
    B页面:
    selectText: function(e){
    var that = this;
    var that_addressInfo ={
    location: e.currentTarget.id
    }
    onfire.fire('setAddressInfo',that_addressInfo);
    uni.navigateBack();
    }

参考来源:https://juejin.im/post/5907f120b123db3ee48d2a4f

收起阅读 »

uni-app中如何使用5+的原生界面控件(包括map、video、livepusher、barcode、nview)

原生控件 nview

uni-app可以调用plus的api操作扩展能力,这块很简单,在app的条件编译里直接写就好了,也不需要plus ready。
但是HTML5 里有很多原生的可视化控件,包括map、video、livepusher、barcode、nview(包括原生头、原生tab),获取这些对象和操作他们需要有特殊写法。
5+app开发时,我们可以用plus.webview.currentWebview获取当前页面,但uni-app里用法不一样,需要这样取当前显示的webview:

const currentWebview = this.$mp.page.$getAppWebview(); //注意相关操作写在APP-PLUS条件编译下

还有一种写法比较冗余,可以获取页面栈中任意一个webview对象:

var pages = getCurrentPages();  
var page = pages[pages.length - 1];  
// #ifdef APP-PLUS  
var currentWebview = page.$getAppWebview(); //页面栈最顶层就是当前webview  
// #endif

注意uni-app不需要像5+App那样等待plus ready,可以直接用。
有了这个currentWebview ,我们就可以做很多事情了,比如:

例子1 创建直播推流

虽然uni-app的nvue页面已经提供了直播组件。但uni-app的vue页面还没有封装,在app里的vue页面使用直播推流就得用这种写法了。(这里指的是推流,如果是拉流,在app侧可直接使用video标签)

var pusher = plus.video.createLivePusher("", {  
    url:'rtmp://testlivesdk.v0.upaiyun.com/live/upyunb',  
    top:'100px',  
    left:'0px',  
    width: '100%',  
    height: '300px',  
    position: 'static'  
});  
currentWebview.append(pusher);

在之前的5+app里,可以使用占位div来布局位置,但在uni-app里,因为没有dom,也没有占位id,所以通过js自己设置原生控件的大小和位置。

例子2 自定义扫码

uni-app的扫码api自带的扫码界面无法有效自定义,大家可以在一个自己的页面里放置一块区域显示扫码控件。

var barcode = plus.barcode.create('barcode', [plus.barcode.QR], {  
    top:'100px',  
    left:'0px',  
    width: '300px',  
    height: '300px',  
    position: 'static'  
});  
//此处未演示扫码成功回调的地址设置,实际请参考HTML5Plus API自行处理  
//注意扫码区域需为正方形,否则影响扫码识别率  
currentWebview.append(barcode);

当然如果使用app-nvue的话,有自带的barcode组件。

例子3 自定义地图

uni-app的原则是vue语法+小程序api。但小程序的api不如plus.map丰富,地图的重度开发者仍然需要plus的map。
uni-app中单独优化了这个地图的获取,通过$getAppMap可直接得到map对象。
然后参考plus.map的api实现更多地图功能。

例子4 给tabbar加个凸起

本例子仅适用于非自定义组件模式
注意tabbar的获取,不是走getCurrentPages,而是用plus.webview.currentWebview()

var centerButtonOnTab = new plus.nativeObj.View("",{top:'500px',left:'160px',height:'50px',width:'50px',backgroundColor:'#FF0000'});  
plus.webview.currentWebview().append(centerButtonOnTab);

这里只是基础演示,大小位置、点击事件,在实际开发中都得自己处理。
插件市场有已经做好的例子:https://ext.dcloud.net.cn/plugin?id=251

如果app端想要高性能的tabbar凸起,建议使用nvue在前端自绘tabbar。

例子5 操作titleNView,给titleNView右上角加个红点

var nTitle = currentWebview.getTitleNView();  
nTitle.drawBitmap("static/reddot.png",{}, {top:'3px',left:'340px',width:'4px',height:'4px'}); //具体尺寸在商用时需自行计算。红点图在附件里。  
//nview的api非常多,具体参考:http://www.html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View

清除刚才绘制的红点

nTitle.reset();

更新:1.5版的HBuilderX已经支持titleNView的button直接设红点了,hello uni-app的模板里运行到app时也能看到相应示例源码。所以本例子实际作用已经过期,此处纯粹演示用。

5+的plus.nativeObj.view,本质是一种类canvas的画布,可以自由的draw内容上去,更新管理也需要自己维护操作。
包括想在原生控件比如视频、地图上加点什么东西,因为HTML的组件是盖不住原生组件的,都可以使用nview来做。

例子6 uni-app可以在vue页面里写web-view组件,这个组件如何用plus api操作?

vue页面里的web-view 组件其实是一个子webview。
在vue里,通过本文开头的代码,先得到当前页面的webview。
然后调用currentWebview.children()方法来获得所有子webview。
因为执行代码的时机不同,可能执行太早会返回空结果。
如果确定页面里有web-view,则可以再延时一下然后再获取一次children。
这样就能拿到这个子webview。
有了子webview对象后,可以用5+丰富的api来进行前进、后退、拦截资源、禁用schema跳转、注入js等各种操作。具体参考https://www.html5plus.org/doc/zh_cn/webview.html

具体请参考web-view组件的文档

继续阅读 »

uni-app可以调用plus的api操作扩展能力,这块很简单,在app的条件编译里直接写就好了,也不需要plus ready。
但是HTML5 里有很多原生的可视化控件,包括map、video、livepusher、barcode、nview(包括原生头、原生tab),获取这些对象和操作他们需要有特殊写法。
5+app开发时,我们可以用plus.webview.currentWebview获取当前页面,但uni-app里用法不一样,需要这样取当前显示的webview:

const currentWebview = this.$mp.page.$getAppWebview(); //注意相关操作写在APP-PLUS条件编译下

还有一种写法比较冗余,可以获取页面栈中任意一个webview对象:

var pages = getCurrentPages();  
var page = pages[pages.length - 1];  
// #ifdef APP-PLUS  
var currentWebview = page.$getAppWebview(); //页面栈最顶层就是当前webview  
// #endif

注意uni-app不需要像5+App那样等待plus ready,可以直接用。
有了这个currentWebview ,我们就可以做很多事情了,比如:

例子1 创建直播推流

虽然uni-app的nvue页面已经提供了直播组件。但uni-app的vue页面还没有封装,在app里的vue页面使用直播推流就得用这种写法了。(这里指的是推流,如果是拉流,在app侧可直接使用video标签)

var pusher = plus.video.createLivePusher("", {  
    url:'rtmp://testlivesdk.v0.upaiyun.com/live/upyunb',  
    top:'100px',  
    left:'0px',  
    width: '100%',  
    height: '300px',  
    position: 'static'  
});  
currentWebview.append(pusher);

在之前的5+app里,可以使用占位div来布局位置,但在uni-app里,因为没有dom,也没有占位id,所以通过js自己设置原生控件的大小和位置。

例子2 自定义扫码

uni-app的扫码api自带的扫码界面无法有效自定义,大家可以在一个自己的页面里放置一块区域显示扫码控件。

var barcode = plus.barcode.create('barcode', [plus.barcode.QR], {  
    top:'100px',  
    left:'0px',  
    width: '300px',  
    height: '300px',  
    position: 'static'  
});  
//此处未演示扫码成功回调的地址设置,实际请参考HTML5Plus API自行处理  
//注意扫码区域需为正方形,否则影响扫码识别率  
currentWebview.append(barcode);

当然如果使用app-nvue的话,有自带的barcode组件。

例子3 自定义地图

uni-app的原则是vue语法+小程序api。但小程序的api不如plus.map丰富,地图的重度开发者仍然需要plus的map。
uni-app中单独优化了这个地图的获取,通过$getAppMap可直接得到map对象。
然后参考plus.map的api实现更多地图功能。

例子4 给tabbar加个凸起

本例子仅适用于非自定义组件模式
注意tabbar的获取,不是走getCurrentPages,而是用plus.webview.currentWebview()

var centerButtonOnTab = new plus.nativeObj.View("",{top:'500px',left:'160px',height:'50px',width:'50px',backgroundColor:'#FF0000'});  
plus.webview.currentWebview().append(centerButtonOnTab);

这里只是基础演示,大小位置、点击事件,在实际开发中都得自己处理。
插件市场有已经做好的例子:https://ext.dcloud.net.cn/plugin?id=251

如果app端想要高性能的tabbar凸起,建议使用nvue在前端自绘tabbar。

例子5 操作titleNView,给titleNView右上角加个红点

var nTitle = currentWebview.getTitleNView();  
nTitle.drawBitmap("static/reddot.png",{}, {top:'3px',left:'340px',width:'4px',height:'4px'}); //具体尺寸在商用时需自行计算。红点图在附件里。  
//nview的api非常多,具体参考:http://www.html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View

清除刚才绘制的红点

nTitle.reset();

更新:1.5版的HBuilderX已经支持titleNView的button直接设红点了,hello uni-app的模板里运行到app时也能看到相应示例源码。所以本例子实际作用已经过期,此处纯粹演示用。

5+的plus.nativeObj.view,本质是一种类canvas的画布,可以自由的draw内容上去,更新管理也需要自己维护操作。
包括想在原生控件比如视频、地图上加点什么东西,因为HTML的组件是盖不住原生组件的,都可以使用nview来做。

例子6 uni-app可以在vue页面里写web-view组件,这个组件如何用plus api操作?

vue页面里的web-view 组件其实是一个子webview。
在vue里,通过本文开头的代码,先得到当前页面的webview。
然后调用currentWebview.children()方法来获得所有子webview。
因为执行代码的时机不同,可能执行太早会返回空结果。
如果确定页面里有web-view,则可以再延时一下然后再获取一次children。
这样就能拿到这个子webview。
有了子webview对象后,可以用5+丰富的api来进行前进、后退、拦截资源、禁用schema跳转、注入js等各种操作。具体参考https://www.html5plus.org/doc/zh_cn/webview.html

具体请参考web-view组件的文档

收起阅读 »

获取webView.getSettings()

获取webView.getSettings():

var Webview = plus.android.importClass("android.webkit.WebView");  
var WebSettings = plus.android.importClass("android.webkit.WebSettings");  
var wv = plus.android.currentWebview();  
var setting = plus.android.invoke(wv, "getSettings");

详见博客:native.js设置可缩放的webview并隐藏缩放控件

继续阅读 »

获取webView.getSettings():

var Webview = plus.android.importClass("android.webkit.WebView");  
var WebSettings = plus.android.importClass("android.webkit.WebSettings");  
var wv = plus.android.currentWebview();  
var setting = plus.android.invoke(wv, "getSettings");

详见博客:native.js设置可缩放的webview并隐藏缩放控件

收起阅读 »

android软件开发之仿淘宝选择规格的实现

  在一些app开发项目中选择商品规格这个功能最容易遇到问题,想要实现需要的全部功能,但一直没有成功,所以就去找了个Demo,学习界面UI采用recyclerview,item里面渲染ViewGroup,根据数据源的数量,往ViewGroup里面添加Textview。这样就可以解决它的每个属性按钮宽高自适应。下面来详细分享一下源码:
/**

  • 测量子view大小 根据子控件设置宽和高

*/

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

{

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// 获得它的父容器为它设置的测量模式和大小

int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);

int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

int modeWidth = MeasureSpec.getMode(widthMeasureSpec);

int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

// 如果是warp_content情况下,记录宽和高

int width = 0;

int height = 0;

/**

  • 记录每一行的宽度,width不断取最大宽度

*/

int lineWidth = 0;

/**

  • 每一行的高度,累加至height

*/

int lineHeight = 0;

int cCount = getChildCount();

// 遍历每个子元素

for (int i = 0; i < cCount; i++)

{

View child = getChildAt(i);

// 测量每一个child的宽和高

measureChild(child, widthMeasureSpec, heightMeasureSpec);

// 得到child的布局管理器

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

// 当前子空间实际占据的宽度

int childWidth = child.getMeasuredWidth() + lp.leftMargin

  • lp.rightMargin;

// 当前子空间实际占据的高度

int childHeight = child.getMeasuredHeight() + lp.topMargin

  • lp.bottomMargin;

/**

  • 如果加入当前child,则超出最大宽度,则的到目前最大宽度给width,类加height 然后开启新行

*/

if (lineWidth + childWidth > sizeWidth)

{

width = Math.max(lineWidth, childWidth);// 取最大的

lineWidth = childWidth; // 重新开启新行,开始记录

// 叠加当前高度,

height += lineHeight;

// 开启记录下一行的高度

lineHeight = childHeight;

} else

// 否则累加值lineWidth,lineHeight取最大高度

{

lineWidth += childWidth;

lineHeight = Math.max(lineHeight, childHeight);

}

// 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较

if (i == cCount - 1)

{

width = Math.max(width, lineWidth);

height += lineHeight;

}

}

setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ?sizeWidth

width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight

height);

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b)

{

mAllViews.clear();

mLineHeight.clear();

int width = getWidth();

int lineWidth = 0;

int lineHeight = 0;

// 存储每一行所有的childView

ListlineViews = new ArrayList<>();

int cCount = getChildCount();

// 遍历所有的孩子

for (int i = 0; i < cCount; i++)

{

View child = getChildAt(i);

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

int childWidth = child.getMeasuredWidth();

int childHeight = child.getMeasuredHeight();

// 如果已经需要换行

if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width)

{

// 记录这一行所有的View以及最大高度

mLineHeight.add(lineHeight);

// 将当前行的childView保存,然后开启新的ArrayList保存下一行的childView

mAllViews.add(lineViews);

lineWidth = 0;// 重置行宽

lineViews = new ArrayList<>();

}

/**

  • 如果不需要换行,则累加

*/

lineWidth += childWidth + lp.leftMargin + lp.rightMargin;

lineHeight = Math.max(lineHeight, childHeight + lp.topMargin

  • lp.bottomMargin);

lineViews.add(child);

}

// 记录最后一行

mLineHeight.add(lineHeight);

mAllViews.add(lineViews);

int left = 0;

int top = 0;

// 得到总行数

int lineNums = mAllViews.size();

for (int i = 0; i < lineNums; i++)

{

// 每一行的所有的views

lineViews = mAllViews.get(i);

// 当前行的最大高度

lineHeight = mLineHeight.get(i);

// 遍历当前行所有的View

for (int j = 0; j < lineViews.size(); j++)

{

View child = lineViews.get(j);

if (child.getVisibility() == View.GONE)

{

continue;

}

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

//计算childView的Marginleft,top,right,bottom

int lc = left + lp.leftMargin;

int tc = top + lp.topMargin;

int rc =lc + child.getMeasuredWidth();

int bc = tc + child.getMeasuredHeight();

child.layout(lc, tc, rc, bc);

left += child.getMeasuredWidth() + lp.rightMargin

  • lp.leftMargin;

}

left = 0;

top += lineHeight;

}

}

接下来是SKU的算法,把选项状态(三种:不能选择,可以选择,已选中)依次对属性按钮做出修改,这里虽然做了一些不必要的循环判断,但胜在功能的实现adapter代码(重点initOptions、canClickOptions和getSelected三个方法)

public class GoodsAttrsAdapter extends BaseRecyclerAdapter {

private SKUInterface myInterface;

private SimpleArrayMap saveClick;

private List stockGoodsList;//商品数据集合

private String[] selectedValue; //选中的属性

private TextView[][] childrenViews; //二维 装所有属性

private final int SELECTED = 0x100;

private final int CANCEL = 0x101;

public GoodsAttrsAdapter(Context ctx, List list, List stockGoodsList) {

super(ctx, list);

this.stockGoodsList = stockGoodsList;

saveClick = new SimpleArrayMap<>();

childrenViews = new TextView[list.size()][0];

selectedValue = new String[list.size()];

for (int i = 0; i < list.size(); i++) {

selectedValue[i] = "";

}

}

public void setSKUInterface(SKUInterface myInterface) {

this.myInterface = myInterface;

}

@Override

public int getItemLayoutId(int viewType) {

return R.layout.item_skuattrs;

}

@Override

public void bindData(RecyclerViewHolder holder, int position, GoodsAttrsBean.AttributesBean item) {

TextView tv_ItemName = holder.getTextView(R.id.tv_ItemName);

SKUViewGroup vg_skuItem = (SKUViewGroup) holder.getView(R.id.vg_skuItem);

tv_ItemName.setText(item.getTabName());

Listchildrens = item.getAttributesItem();

int childrenSize = childrens.size();

TextView[] textViews = new TextView[childrenSize];

for (int i = 0; i < childrenSize; i++) {

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

params.setMargins(5, 5, 5, 0);

TextView textView = new TextView(mContext);

textView.setGravity(Gravity.CENTER);

textView.setPadding(15, 5, 15, 5);

textView.setLayoutParams(params);

textView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.saddlebrown));

textView.setText(childrens.get(i));

textView.setTextColor(ContextCompat.getColor(mContext, R.color.white));

textViews[i] = textView;

vg_skuItem.addView(textViews[i]);

}

childrenViews[position] = textViews;

initOptions();

canClickOptions();

getSelected();

}

private int focusPositionG, focusPositionC;

private class MyOnClickListener implements View.OnClickListener {

//点击操作 选中SELECTED 取消CANCEL

private int operation;

private int positionG;

private int positionC;

public MyOnClickListener(int operation, int positionG, int positionC) {

this.operation = operation;

this.positionG = positionG;

this.positionC = positionC;

}

@Override

public void onClick(View v) {

focusPositionG = positionG;

focusPositionC = positionC;

String value = childrenViews[positionG][positionC].getText().toString();

switch (operation) {

case SELECTED:

saveClick.put(positionG, positionC + "");

selectedValue[positionG] = value;

myInterface.selectedAttribute(selectedValue);

break;

case CANCEL:

saveClick.put(positionG, "");

for (int l = 0; l < selectedValue.length; l++) {

if (selectedValue[l].equals(value)) {

selectedValue[l] = "";

break;

}

}

myInterface.uncheckAttribute(selectedValue);

break;

}

initOptions();

canClickOptions();

getSelected();

}

}

class MyOnFocusChangeListener implements View.OnFocusChangeListener {

private int positionG;

private int positionC;

public MyOnFocusChangeListener(int positionG, int positionC) {

this.positionG = positionG;

this.positionC = positionC;

}

@Override

public void onFocusChange(View v, boolean hasFocus) {

String clickpositionC = saveClick.get(positionG);

if (hasFocus) {

v.setBackgroundColor(ContextCompat.getColor(mContext, R.color.pink));

if (TextUtils.isEmpty(clickpositionC)) {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

} else if (clickpositionC.equals(positionC + "")) {

} else {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

}

} else {

v.setBackgroundColor(ContextCompat.getColor(mContext, R.color.saddlebrown));

if (TextUtils.isEmpty(clickpositionC)) {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.white));

} else if (clickpositionC.equals(positionC + "")) {

} else {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.white));

}

}

}

}

/**

  • 初始化选项(不可点击,焦点消失)

*/

private void initOptions() {

for (int y = 0; y < childrenViews.length; y++) {

for (int z = 0; z < childrenViews[y].length; z++) {//循环所有属性

TextView textView = childrenViews[y][z];

textView.setEnabled(false);

textView.setFocusable(false);

textView.setTextColor(ContextCompat.getColor(mContext, R.color.gray));//变灰

}

}

}

/**

  • 找到符合条件的选项变为可选

*/

private void canClickOptions() {

for (int i = 0; i < childrenViews.length; i++) {

for (int j = 0; j < stockGoodsList.size(); j++) {

boolean filter = false;

List goodsInfo = stockGoodsList.get(j).getGoodsInfo();

for (int k = 0; k < selectedValue.length; k++) {

if (i == k || TextUtils.isEmpty(selectedValue[k])) {

continue;

}

if (!selectedValue[k].equals(goodsInfo

.get(k).getTabValue())) {

filter = true;

break;

}

}

if (!filter) {

for (int n = 0; n < childrenViews[i].length; n++) {

TextView textView = childrenViews[i][n];//拿到所有属性TextView

String name = textView.getText().toString();

//拿到属性名称

if (goodsInfo.get(i).getTabValue().equals(name)) {

textView.setEnabled(true);//符合就变成可点击

textView.setFocusable(true); //设置可以获取焦点

//不要让焦点乱跑

if (focusPositionG == i && focusPositionC == n) {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

textView.requestFocus();

} else {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.white));

}

textView.setOnClickListener(new MyOnClickListener(SELECTED, i, n) {

});

textView.setOnFocusChangeListener(new MyOnFocusChangeListener(i, n) {

});

}

}

}

}

}

}

/**

  • 找到已经选中的选项,让其变红

*/

private void getSelected() {

for (int i = 0; i < childrenViews.length; i++) {

for (int j = 0; j < childrenViews[i].length; j++) {//拿到每行属性Item

TextView textView = childrenViews[i][j];//拿到所有属性TextView

String value = textView.getText().toString();

for (int m = 0; m < selectedValue.length; m++) {

if (selectedValue[m].equals(value)) {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.red));

textView.setOnClickListener(new MyOnClickListener(CANCEL, i, j) {

});

}

}

}

}

}

}

  好了,到这里就算是结束了,如果还是存在有疑问的地方,大家可以留言咨询。
  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

继续阅读 »

  在一些app开发项目中选择商品规格这个功能最容易遇到问题,想要实现需要的全部功能,但一直没有成功,所以就去找了个Demo,学习界面UI采用recyclerview,item里面渲染ViewGroup,根据数据源的数量,往ViewGroup里面添加Textview。这样就可以解决它的每个属性按钮宽高自适应。下面来详细分享一下源码:
/**

  • 测量子view大小 根据子控件设置宽和高

*/

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

{

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// 获得它的父容器为它设置的测量模式和大小

int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);

int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

int modeWidth = MeasureSpec.getMode(widthMeasureSpec);

int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

// 如果是warp_content情况下,记录宽和高

int width = 0;

int height = 0;

/**

  • 记录每一行的宽度,width不断取最大宽度

*/

int lineWidth = 0;

/**

  • 每一行的高度,累加至height

*/

int lineHeight = 0;

int cCount = getChildCount();

// 遍历每个子元素

for (int i = 0; i < cCount; i++)

{

View child = getChildAt(i);

// 测量每一个child的宽和高

measureChild(child, widthMeasureSpec, heightMeasureSpec);

// 得到child的布局管理器

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

// 当前子空间实际占据的宽度

int childWidth = child.getMeasuredWidth() + lp.leftMargin

  • lp.rightMargin;

// 当前子空间实际占据的高度

int childHeight = child.getMeasuredHeight() + lp.topMargin

  • lp.bottomMargin;

/**

  • 如果加入当前child,则超出最大宽度,则的到目前最大宽度给width,类加height 然后开启新行

*/

if (lineWidth + childWidth > sizeWidth)

{

width = Math.max(lineWidth, childWidth);// 取最大的

lineWidth = childWidth; // 重新开启新行,开始记录

// 叠加当前高度,

height += lineHeight;

// 开启记录下一行的高度

lineHeight = childHeight;

} else

// 否则累加值lineWidth,lineHeight取最大高度

{

lineWidth += childWidth;

lineHeight = Math.max(lineHeight, childHeight);

}

// 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较

if (i == cCount - 1)

{

width = Math.max(width, lineWidth);

height += lineHeight;

}

}

setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ?sizeWidth

width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight

height);

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b)

{

mAllViews.clear();

mLineHeight.clear();

int width = getWidth();

int lineWidth = 0;

int lineHeight = 0;

// 存储每一行所有的childView

ListlineViews = new ArrayList<>();

int cCount = getChildCount();

// 遍历所有的孩子

for (int i = 0; i < cCount; i++)

{

View child = getChildAt(i);

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

int childWidth = child.getMeasuredWidth();

int childHeight = child.getMeasuredHeight();

// 如果已经需要换行

if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width)

{

// 记录这一行所有的View以及最大高度

mLineHeight.add(lineHeight);

// 将当前行的childView保存,然后开启新的ArrayList保存下一行的childView

mAllViews.add(lineViews);

lineWidth = 0;// 重置行宽

lineViews = new ArrayList<>();

}

/**

  • 如果不需要换行,则累加

*/

lineWidth += childWidth + lp.leftMargin + lp.rightMargin;

lineHeight = Math.max(lineHeight, childHeight + lp.topMargin

  • lp.bottomMargin);

lineViews.add(child);

}

// 记录最后一行

mLineHeight.add(lineHeight);

mAllViews.add(lineViews);

int left = 0;

int top = 0;

// 得到总行数

int lineNums = mAllViews.size();

for (int i = 0; i < lineNums; i++)

{

// 每一行的所有的views

lineViews = mAllViews.get(i);

// 当前行的最大高度

lineHeight = mLineHeight.get(i);

// 遍历当前行所有的View

for (int j = 0; j < lineViews.size(); j++)

{

View child = lineViews.get(j);

if (child.getVisibility() == View.GONE)

{

continue;

}

MarginLayoutParams lp = (MarginLayoutParams) child

.getLayoutParams();

//计算childView的Marginleft,top,right,bottom

int lc = left + lp.leftMargin;

int tc = top + lp.topMargin;

int rc =lc + child.getMeasuredWidth();

int bc = tc + child.getMeasuredHeight();

child.layout(lc, tc, rc, bc);

left += child.getMeasuredWidth() + lp.rightMargin

  • lp.leftMargin;

}

left = 0;

top += lineHeight;

}

}

接下来是SKU的算法,把选项状态(三种:不能选择,可以选择,已选中)依次对属性按钮做出修改,这里虽然做了一些不必要的循环判断,但胜在功能的实现adapter代码(重点initOptions、canClickOptions和getSelected三个方法)

public class GoodsAttrsAdapter extends BaseRecyclerAdapter {

private SKUInterface myInterface;

private SimpleArrayMap saveClick;

private List stockGoodsList;//商品数据集合

private String[] selectedValue; //选中的属性

private TextView[][] childrenViews; //二维 装所有属性

private final int SELECTED = 0x100;

private final int CANCEL = 0x101;

public GoodsAttrsAdapter(Context ctx, List list, List stockGoodsList) {

super(ctx, list);

this.stockGoodsList = stockGoodsList;

saveClick = new SimpleArrayMap<>();

childrenViews = new TextView[list.size()][0];

selectedValue = new String[list.size()];

for (int i = 0; i < list.size(); i++) {

selectedValue[i] = "";

}

}

public void setSKUInterface(SKUInterface myInterface) {

this.myInterface = myInterface;

}

@Override

public int getItemLayoutId(int viewType) {

return R.layout.item_skuattrs;

}

@Override

public void bindData(RecyclerViewHolder holder, int position, GoodsAttrsBean.AttributesBean item) {

TextView tv_ItemName = holder.getTextView(R.id.tv_ItemName);

SKUViewGroup vg_skuItem = (SKUViewGroup) holder.getView(R.id.vg_skuItem);

tv_ItemName.setText(item.getTabName());

Listchildrens = item.getAttributesItem();

int childrenSize = childrens.size();

TextView[] textViews = new TextView[childrenSize];

for (int i = 0; i < childrenSize; i++) {

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

params.setMargins(5, 5, 5, 0);

TextView textView = new TextView(mContext);

textView.setGravity(Gravity.CENTER);

textView.setPadding(15, 5, 15, 5);

textView.setLayoutParams(params);

textView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.saddlebrown));

textView.setText(childrens.get(i));

textView.setTextColor(ContextCompat.getColor(mContext, R.color.white));

textViews[i] = textView;

vg_skuItem.addView(textViews[i]);

}

childrenViews[position] = textViews;

initOptions();

canClickOptions();

getSelected();

}

private int focusPositionG, focusPositionC;

private class MyOnClickListener implements View.OnClickListener {

//点击操作 选中SELECTED 取消CANCEL

private int operation;

private int positionG;

private int positionC;

public MyOnClickListener(int operation, int positionG, int positionC) {

this.operation = operation;

this.positionG = positionG;

this.positionC = positionC;

}

@Override

public void onClick(View v) {

focusPositionG = positionG;

focusPositionC = positionC;

String value = childrenViews[positionG][positionC].getText().toString();

switch (operation) {

case SELECTED:

saveClick.put(positionG, positionC + "");

selectedValue[positionG] = value;

myInterface.selectedAttribute(selectedValue);

break;

case CANCEL:

saveClick.put(positionG, "");

for (int l = 0; l < selectedValue.length; l++) {

if (selectedValue[l].equals(value)) {

selectedValue[l] = "";

break;

}

}

myInterface.uncheckAttribute(selectedValue);

break;

}

initOptions();

canClickOptions();

getSelected();

}

}

class MyOnFocusChangeListener implements View.OnFocusChangeListener {

private int positionG;

private int positionC;

public MyOnFocusChangeListener(int positionG, int positionC) {

this.positionG = positionG;

this.positionC = positionC;

}

@Override

public void onFocusChange(View v, boolean hasFocus) {

String clickpositionC = saveClick.get(positionG);

if (hasFocus) {

v.setBackgroundColor(ContextCompat.getColor(mContext, R.color.pink));

if (TextUtils.isEmpty(clickpositionC)) {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

} else if (clickpositionC.equals(positionC + "")) {

} else {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

}

} else {

v.setBackgroundColor(ContextCompat.getColor(mContext, R.color.saddlebrown));

if (TextUtils.isEmpty(clickpositionC)) {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.white));

} else if (clickpositionC.equals(positionC + "")) {

} else {

((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.white));

}

}

}

}

/**

  • 初始化选项(不可点击,焦点消失)

*/

private void initOptions() {

for (int y = 0; y < childrenViews.length; y++) {

for (int z = 0; z < childrenViews[y].length; z++) {//循环所有属性

TextView textView = childrenViews[y][z];

textView.setEnabled(false);

textView.setFocusable(false);

textView.setTextColor(ContextCompat.getColor(mContext, R.color.gray));//变灰

}

}

}

/**

  • 找到符合条件的选项变为可选

*/

private void canClickOptions() {

for (int i = 0; i < childrenViews.length; i++) {

for (int j = 0; j < stockGoodsList.size(); j++) {

boolean filter = false;

List goodsInfo = stockGoodsList.get(j).getGoodsInfo();

for (int k = 0; k < selectedValue.length; k++) {

if (i == k || TextUtils.isEmpty(selectedValue[k])) {

continue;

}

if (!selectedValue[k].equals(goodsInfo

.get(k).getTabValue())) {

filter = true;

break;

}

}

if (!filter) {

for (int n = 0; n < childrenViews[i].length; n++) {

TextView textView = childrenViews[i][n];//拿到所有属性TextView

String name = textView.getText().toString();

//拿到属性名称

if (goodsInfo.get(i).getTabValue().equals(name)) {

textView.setEnabled(true);//符合就变成可点击

textView.setFocusable(true); //设置可以获取焦点

//不要让焦点乱跑

if (focusPositionG == i && focusPositionC == n) {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));

textView.requestFocus();

} else {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.white));

}

textView.setOnClickListener(new MyOnClickListener(SELECTED, i, n) {

});

textView.setOnFocusChangeListener(new MyOnFocusChangeListener(i, n) {

});

}

}

}

}

}

}

/**

  • 找到已经选中的选项,让其变红

*/

private void getSelected() {

for (int i = 0; i < childrenViews.length; i++) {

for (int j = 0; j < childrenViews[i].length; j++) {//拿到每行属性Item

TextView textView = childrenViews[i][j];//拿到所有属性TextView

String value = textView.getText().toString();

for (int m = 0; m < selectedValue.length; m++) {

if (selectedValue[m].equals(value)) {

textView.setTextColor(ContextCompat.getColor(mContext, R.color.red));

textView.setOnClickListener(new MyOnClickListener(CANCEL, i, j) {

});

}

}

}

}

}

}

  好了,到这里就算是结束了,如果还是存在有疑问的地方,大家可以留言咨询。
  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

收起阅读 »