首页 文章 精选 留言 我的

精选列表

搜索[剪贴板历史],共10004篇文章
优秀的个人博客,低调大师

网盘成为“历史” 云端数据何去何从

华为网盘、新浪微盘、UC网盘、金山快盘、腾讯微云等云存储服务平台接连宣布将关闭或调整个人用户存储等服务,网民热衷的“云存储”几乎集体沦陷。而对于已经习惯使用“网盘”的企业来说,要想安全、稳定的进行云数据分享,就需要为员工的网盘应用开辟出一条新路。 网盘全体“关机”,企业用户也中招 舆论认为,导致网盘系统全面“关机”的原因主要有两点:其一,网盘已经成为互联网内容传播非常重要的一种途径,很容易成为非法信息传播的“温床”,国家加大力度监管势在必行;其二,网盘业务目前多数不盈利,继续运营不但耗时耗力,还面临触犯法规的管风险,因此很多“未涉事”的企业也顺势关停。 值得注意的是,免费网盘拥有存储容量大、成本为零、多设备同步的优点,因此在企业数据分享工具中所占比例非常高。亚信安全网络安全监测实验室数据显示,每5位员工中就有一位偷偷地使用网盘,19%的员工将公司敏感信息存储在网盘,如果企业用户不能及时提取网盘中的数据,则会面临重大的数据丢失风险。网盘资料亦成为黑客和病毒的“避风港”,如若黑客通过网盘发送恶意软件,用户在文件分享时很容易造成大规模感染。 【公共云存储存在诸多隐患】 显然,传统“免费“的网盘业务不仅在业务持续性上得不到保障,而且在安全性上堪忧。如果不能突破上述瓶颈,很有可能就被彻底淘汰。 存储挑战将至,数据安全不容忽视 由于传统网盘业务面临的巨大挑战,企业用户将不得不寻求新的解决方案。一种思路是,为每名员工配发移动存储设备,解决大容量文件分享的需要。但这种“走回头路”的方法不现实,也不符合企业级应用、移动化办公的要求。另外一种思路是,企业自行建立“网盘”或是购买“云存储”系统。调查显示,后者被企业信息主管广泛接收,这种方式不仅更稳定,而且更便捷、更可控、更安全。 基于企业云存储服务存在的问题,亚信安全移动安全及服务产品总监刘政平表示:“公有云存储的安全性长期困扰着许多企业的安全主管。因此,在自行建立云存储系统时,用户不但会考虑大容量文件分享的便捷性,还会特别关注的数据加密、认证审计等安全性的设计。而作为成熟的云存储解决方案,亚信安全SafeSync企业安全云盘可以帮助企业用户解决安全、管理和投资回报率的挑战。” 首先,在提供跨平台同步及云分享的同时,SafeSync支持团队文件权限设定和在线编辑功能,客户端与云间的数据传输均采用了AES256位加密通信保护,并拥有防毒过滤和防泄密功能。每一个接入SafeSync云端的账户都拥有独立存储空间,并可以充分保障数据的安全性。 其次,作为企业自建的私有网盘系统,SafeSync并不面向一般的互联网用户,用户账号对应的是员工个体。企业对员工的所有操作行为都能进行审计,可以回溯追责,实现了数据访问的自主可控。 最后,与个人网盘存储应用不同,SafeSync部署在企业内网,大文件分享、邮件大附件传输的速度将会更快、更稳定。在新媒体采集和储存、设计档案传递、合作伙伴交互、为外部客户展示、培训供应商等多个应用场景,都展现出强大的优势。 从整体上来说,随着传统网盘应用纷纷调整、关闭存储服务,SafeSync凭借着稳定性、安全性、传输速度等方面的优势,已经成为传统网盘应用的最佳替代。 本文转自d1net(转载)

优秀的个人博客,低调大师

微信公众平台的发展历史

2012年8月17日,公众平台正式向普通用户开放。于2012年08月23日正式上线,曾命名为“官号平台”和“媒体平台”,创造更好的用户体验,形成一个不一样的生态循环。2012年11月29日,公众平台群发系统全面升级,新增图文消息编辑功能,并对发送的内容进行敏感词和安全性检测。2013年2月6日,公众平台做了如下调整。1)增加高级功能选项,用户可以在编辑模式和开发模式中选择一个使用。2)设置选项中只保留账号信息和公众号手机助手2项,被添加消息自动回复和自定义规则回复2个重要功能选项删除。3)公众平台全面开启实名认证。2013年3月19日,公众平台开放“自定义菜单”API内测申请(仅限企业和机构申请)。2013年6月 新增自定义LBS数据2013年8月5日,伴随着微信5.0的发布,公众平台也进行了大幅调整,主要包括以下几个方面。1)公众账号被划分为订阅号和服务号,服务号可申请自定义菜单。2)运营主体为组织,可选择成为服务号或订阅号;运营主体为个人,只能申请订阅号。3)编辑图文消息可选填作者。2013年8月29日,公众平台新增数据统计功能,包括用户管理分析、群发图文消息分析、用户消息分析和接口调用分析,数据从2013年7月1日开始统计。2013年10月29日,公众平台全面改版,主要更新内容如下。1)开放全新的认证体系,服务号可申请微信认证,审核通过后,即可获得微信认证标识并同时拥有高级接口的使用权限。2)开放高级接口。服务号通过微信认证后,可以获得的高级接口包括语音识别、客服接口、OAuth2.0网页授权、生成带参数二维码、获取用户地理位置、获取用户基本信息、获取关注列表和用户分组接口。3)新增开发者问答系统,为开发者提供一个互动交流平台。4)公众平台界面进行了全新改版。公众平台导航栏由横向改为竖向,界面风格及各类细节都做了调整,使用起来更加方便。2013年12月2日,公众平台新增“测试账号”功能,开发者可以使用手机号申请公众平台接口测试账号,直接体验和测试公众平台开放的所有接口。2013年12月24日,公众平台针对订阅号做了重要更新。政府、传统媒体、明星等非企业性质的订阅号可以申请微信认证,通过微信认证的订阅号可获得自定义菜单接口权限。2014年6月6日,微信平台公布微信整顿公众号集赞行为处理机制,微信公众号累计发现一次集赞行为,封号7天;累计发现两次集赞行为,封号15天;累计发现3次集赞行为,封号30天;累计发现4次集赞行为,永久封号且不解封。2014年6月9日起,微信采用技术+人工举报方式对集赞行为进行全平台清理和规范。

优秀的个人博客,低调大师

从 Web 图标演进历史看最佳实践

导读:在产品中适当使用图标,可以让产品更生动,也更简洁。在前端项目中,处理和引入图标都是必不可少的环节。在 Web 产品中引入图标,大致经历过如下几个阶段:使用独立的图片来引入图标、使用 CSS sprites 技术、使用字体图标(font icons)、使用 SVG(inline SVG/SVG sprites)、在前端视图层框架中封装组件。本文将简单梳理一下图标相关的工作流程的演进,以及我们在百度设计语言系统推进过程中相关的一些尝试。 全文7006字,预计阅读时间 14分钟。 一、使用独立图片 在过去有很长一段时间,前端是通过引入图片来承载图标。在没有 CSS 支持的时代,用 <img> 标签引入图标图片是唯一的可能。 <ahref="/contact.html"><imgsrc="mail.jpg"alt="email"></a> 到了 CSS 支持背景图以后,人们开始使用 background-image 来引入一个个小图片,但本质上没有改变每个图标都使用单独图片的问题。 显然,这样的方式在有很多图标的网页中将发起很多 HTTP 请求,占用浏览器的并行请求数量,导致整体加载时间缓慢,体验很差。对于有些鼠标悬浮后切换图标的设计,这种方式还会出现第一次切换时需要等待图标加载的问题。(但是令人沮丧的是,直到现在还有网站依然保留着这样的方式。) 二、CSS Sprite 后来在大约本世纪初的头几年,人们找到了一种新的技巧:通过将图片合并技术(image sprite)引入前端,将数量众多的图标图片进行巧妙拼合,并且在样式中通过 background-position 来通过不同位置匹配不同的图标进行显示。例如: .toolbtn{background:url(icons.png);display:inline-block;height:20px;width:20px;}#btn1{background-position:-20px0px;}#btn2{background-position:-40px0px;} 虽然这种方式相较于每个小图标一个图片文件,只会发起一次 HTTP 请求,对性能更加友好,但是依然有着如下问题: 拼合后的图片非常难以维护,需要手动精心调整。虽然也有一些自动生成“雪碧图”的工具,但由于 background-position 这种方式的限制,生成逻辑无法保证灵活适应各种可能的使用场景。 图片来自https://www.smashingmagazine.com/2012/04/css-sprites-revisited/ 当一个项目图标很多时,图片会在整体下载完以后才显示,可能会导致一段较长的时间内所有图标都无法显示。同时由于高昂的维护成本,很难做到按需加载图标,往往整站的图标都会全部合并到同一个“雪碧图”中。 图标颜色是确定的,无法在前端根据内容上下文灵活调整图标的颜色。 图片尺寸是固定的,进行缩放后很难保证图标的显示效果。 在这个时代,设计师和工程师协作的模式一般来说都是设计师将设计好的图标文件交付给工程师,由工程师来通过图片编辑工具或者一些雪碧图生成器来维护拼合后的图片,效率和可维护性都非常堪忧。 三、字体图标的崛起 由于图标从某种程度上来看可以被视为“象形文字”,所以当 CSS 开始支持 @font-face 引入 web font,人们立刻想到了用它来载入、显示图标。从 2012 年至今,提供大量免费图标的 FontAwesome 就取得了很大的成功(后来开始商业化的 FontAwesome 5 的甚至为他们在 Kickstarter 上筹集到了一百万美金),各种字体图标平台也层出不穷。阿里的 iconfont.cn 平台从多年前开始就已经成为国内最受欢迎的图标托管、共享、管理平台。可以说字体图标时至今日还是最热门的 web 图标方案之一。 字体图标的原理非常简单,通过占用一些 Unicode 字符编码(通常是私人使用区,U+E000-U+F8FF、U+F0000-U+FFFFD 以及 U+100000-U+10FFFD 范围内)并为其绘制字形,同时生成好一堆预定义的图标名 class name,通过 web font 的方式加载资源,通过对应的 class name 来引用图标。由于各个浏览器对 web font 支持的字体格式兼容性有差异,往往需要生成多个格式的字体供浏览器进行选择性加载: /* iconfont.cn 生成的样式文件大致如下:*/@font-face{font-family:"iconfont";src:url('iconfont.eot');/*IE9*/src:url('iconfont.eot#iefix')format('embedded-opentype'),/*IE6-IE8*/url('iconfont.woff2')format('woff2'),url('iconfont.woff')format('woff'),url('iconfont.ttf')format('truetype'),/*chrome,firefox,opera,Safari,Android,iOS4.2+*/url('iconfont.svg#iconfont')format('svg');/*iOS4.1-*/}.iconfont{font-family:"iconfont"!important;}.icon-flag:before{content:"\e233";} 在 HTML 中使用: <iclass="icon-flag"></i> 字体图标虽然也很难维护,但是相比“雪碧图”还是有不少明显的优势: 基于轮廓字体格式的字体图标是通过贝塞尔曲线描述的,可以任意伸缩并且保持显示效果不失真,这在移动端尤为重要。 字体可以轻易地使用 CSS 设置颜色。 但我们可以看出,这个方案对使用者的工程能力已经有所要求。虽然在这个时代,多数业内前端团队已经都有了初步的工程化能力,开始使用诸如 Grunt/Gulp 甚至 webpack 等工具,基于 Node + npm 去定制各自团队的工程化方案了,但是编排每个图标的 Unicode 编码、生成对应的 CSS 代码就已经有比较大的工作量,更别说生成这么多格式的字体文件,普通工程师根本无从下手。这也是 iconfont.cn 吸引大量用户的重要原因。重度依赖第三方平台,自己建设成本又比较高,使得图标的可维护性依然存在一定的痛点。 另外,虽然字体图标解决了一些“雪碧图”的体验问题,它也带来了一些新问题: 字体文件加载需要时间,在文件加载完成前,图标是无法显示的,内容就很容易发生闪烁。在某些浏览器下,处于私有使用区的图标在默认字体下甚至会显示为一个方块字符。 图片来自https://github.blog/2016-02-22-delivering-octicons-with-svg/ 这一点实际上和“雪碧图”有着很大的共同点。虽然我们可以使用 data URI 来将资源内联,事实上有很长时间我们也的确使用过将图片或者字体通过 data URI 编码后内联到 HTML 的方式来避免这个加载的时间差,但是编码本身会增加内容 1/3 左右的尺寸,实际上只能算是一种取舍和妥协。更别说字体图标需要生成如此多格式的字体,内联到 HTML 网页性能将大打折扣。 可访问性问题:对于患有视力障碍使用读屏器的用户,由于字体图标实际由字符承载,无论字体是否加载完毕,读屏器都无法正常朗读其内容,在默认的状态下甚至会读出“unpronounceable”这样不符合预期的内容,可以想象如果一个网页大量使用字体图标却没有逐个标注 aria-hidden 这样的语义标记,会对读屏器用户产生多大的困惑。 四、SVG 图标 SVG 天生就带有可伸缩(SVG 中的 S)特性,非常适合用来实现图标。同时,SVG 是文本文件,同时诸多支持矢量编辑的设计工具都支持通过 SVG 导出,设计师可以直接交付给工程师使用,也不再需要生成字体文件,大大缓解了可维护性上的痛点。但如果将它当成图片,通过 <img> 或 CSS background-image 来引入,仅仅有这些优势还不足以撼动图标字体的地位。 4.1 内联 SVG SVG 的真正强大之处在于,当将其内联入 HTML 内容,那么它的文档模型将可以被该页面的 JS/CSS 访问和操作。这为 web 图标开启了新的篇章: 可以通过 CSS 控制图标的颜色甚至具体样式,使得受业务逻辑控制的动画图标成为可能。 在显示效果上,字体图标由于本质上被视为文本,将受到浏览器的文字抗锯齿算法的影响,在特定操作系统、浏览器、字体设置下视觉效果可能会不那么“保真”。而 SVG 被视为图片进行渲染,不会受文字抗锯齿算法影响,渲染效果更加原汁原味。 SVG 内联入 HTML 内容并不需要进行编码,重复的 SVG 内容也是对 gzip 友好的,对 HTML 加载速度的性能损耗很小。 不需要发起资源请求,可以随着 HTML 内容进行流式加载和渲染,不会产生任何闪动的体验问题。 图标加载可以做到完全按需,当前页面没有用到的图标都不会输出。 SVG 可以通过 <title> 元素标记内容,对读屏器友好。 相比于通过图片资源加载或者图标字体,只有一个劣势: 图标成为 HTML 内容的一部分,不再能在 CSS 中指定需要使用的图标了。当然这一点从我们的实践中来看,并不构成很大的阻碍。 虽然内联 SVG 有很多优势,但是在这个阶段,在开发时使用它们却不像字体图标那么简单直接(引入一个 CSS,前端就能任意使用),需要对工程有一定侵入性的处理。GitHub 在 2016 年全面启用了内联 SVG 的方案,他们的技术栈是 Ruby 的后端渲染,通过服务端脚本定义的 helper 函数来进行图标字体的调用: <%=octicon(:symbol=>"plus")%> 输出: <svgaria-hidden="true"class="octiconocticon-plus"width="12"height="16"role="img"version="1.1"viewBox="001216"><pathd="M129H7v5H5V9H0V7h5V2h2v5h5v2z"></path></svg> 4.2 SVG Sprite 由于 SVG 支持一个 <use> 元素,可以从内联的 SVG 中选取特定内容出来作为独立的 SVG 进行显示,所以人们受 CSS sprite 的启发,也设计了一个 SVG sprite 方案。引入整个 SVG sprite 的资源仅需要内联一个 <svg> 元素: <svg><defs><symbolid="shape-icon-1"><!--iconpathsandshapes--><symbol><symbolid="shape-icon-2"><!--iconpathsandshapes--><symbol><!--etc--></defs></svg> 使用时: <svgviewBox="001616"class="icon"><usexlink:href="#shape-icon-1"></use></svg> 同时,也有不少基于 Grunt/Gulp/webpack 的构建方案,来快速生成 SVG sprite。 这种方式主要的问题在于: 不容易按需引入图标。 在各个场景使用时比较繁琐。 五、前端组件框架的时代 终于到了我们现在所处的时代,这是一个 web 端渲染逻辑被移到前端,前端工程方向被组件化框架主导的时代。在使用 React/Vue/Angular/Svelte/…… 等各种框架的过程中,我们已经习惯于将视图逻辑通过组件进行拆解和复用。那么我们很自然地就可以通过设计图标组件来对底层方案进行一层封装,暴露给前端更简单直接的 API 来使用图标。要注意的是,这并没有在根本上改变 web 图标渲染的方式,底层依然是基于前文提到的各种方案。在不使用这些视图层框架的项目中,我们依然仰赖使用上述 low-level 的实现来进行开发。 当然,从各方面综合比较,封装内联 SVG 应该是当前最佳的选择。上文 GitHub 后端 helper 的方案对应当前前端的技术方案,实际上就是基于内联 SVG 的图标组件。npm 上目前也有很多基于各个组件框架开发的图标组件,包括 FontAwesome 都已经内置了 SVG、React/Vue 组件等更现代化的方案。 既然体验问题已经由内联 SVG 得到了比较好的解决,那么在这个阶段我们就有更多的精力去更多地考虑研发效能、一致性、开发体验的问题了。从我们在百度内部以往的实践中来看,存在这如下的一些问题: 工作流程缺乏最佳实践,由于长期各个团队有着较为独立的技术演变,使用的 web 图标方案并不统一。 整个大体系下跨团队的设计师并没有很好地共享图标资源,存在一定的重复设计。 有图标组件库,但是图标有限,业务需要新增图标时设计师往往还是将图标线下交付给工程师,前端通过一些类似 svg-icon-loader 的方案将图标引入项目,但方案往往各不相同。一旦引入这样的流程,相当于给图标在特定项目中新增了一个 fork 版本,日后想做设计风格的统一调整就需要业务跟进修改,成本很高。 针对 SVG 图标组件,我们没有一个类似 iconfont.cn 的平台进行流程上的收拢,也没有自动化的代码包导出、发布能力。 理想情况下,我们希望达成如下目标: 图标设计师维护图标源文件,发布以后没有任何人工干预造成流程分叉,有一个固定的图标库平台提供 single source of truth。 每个团队能根据自身技术栈,选择需要导出的组件实现类型(React/Vue/San/...)。 图标组件库中的图标数据会被自动优化、压缩。 图标组件库应该是可以跟随图标库的数据更新升级的。 目前我们在推进百度设计语言系统的过程中,和工程效能团队一起,设计了如下整体方案: 图标平台整体流程 5.1 图标管理平台 这个平台可以视为是一个简单的图标 CMS,可以创建/管理图标库,图标设计师负责来在其中添加、管理图标。在完成数据的更新后,可以选择发布当前图标输出到 API。这个 API 返回图标库中图标的图形数据(SVG 源文件)和元数据,在整个流程中主要有两个消费者:给设计团队使用的 Sketch 插件,以及前端的编译/发布服务。我们允许图标库发布时通过 webhook 配置需要通知的编译服务,所以有必要的话,不同的使用方也可以选择自己自定义整套编译发布的流程。 5.2 Sketch 插件 我们给设计团队提供了联通图标管理平台的 Sketch 插件,设计师可以在插件中快速搜索需要的图标进行使用。通过我们的插件导出在线标注稿后,标注稿上就会自动标注图标在图标平台中的唯一标识符,这也是我们用来生成图标组件时用的标识符,前端工程师通过它就能直接从图标组件包中引入对应的图标组件。 5.3 优化/编译/发布服务 这个服务在图标库 API 触发更新时主要做了三件事: 优化。从 API 读取图标数据,并且将源文件通过 SVGO 进行初步优化。由于我们希望图标组件内联到 HTML 以后可以通过 CSS 灵活修改颜色,所以对于常见的单色图标,我们需要去除所有硬编码的颜色,在有必要时设置为 currentColor。在这一步我们通过 svgson 遍历 SVG 元素处理相关逻辑。 编译。得到了优化过的图标数据,我们需要根据他们来生成我们的图标组件包。在这里我们提供了多个框架的组件包模板,每个模板中都已经提供了对应各自框架的图标组件工厂函数,只需要通过脚本在模板中注入图标数据,即可根据平台数据灵活生成各个业务所需要的组件包。 发布。根据在 webhook 回调路径中的配置,我们可以指定需要发布的包的名称,描述等信息。版本号的逻辑也比较简单: 删除/改名图标:major + 1 新增图标:minor + 1 修改图标内容:patch + 1 5.4 图标包模板 编译服务对包模板(boilerplate)仅有的约定是: 编译服务会在特定目录输出图标数据。 编译服务会依次调用特定的 npm script。 模板提供者需要提供图标组件的具体实现,以及将图标数据转换为前端代码的构建脚本。如果没有特殊的需求,直接使用我们提供的 React/Vue 等框架下的组件模板,就可以获得高质量的前端图标组件实现了。 通过编译服务发布完成以后,前端工程师只需要知道:1. 使用的图标来自哪个 npm 包 2. 这个图标叫什么名字,即可快速在前端项目中引入图标。同时,整个流程保证了设计师产出的设计稿、前端实现的一致,并且可以从图标平台中心化地控制升级。 六、总结 在 Web 产品中引入图标我们前端工程师做过很多探索,也产出过很多相关的辅助工具来完善整个协作流程。在目前组件化开发的大背景下,我们通过分析各个方案的优缺点,建立起一套当下的“最佳实践”,减少了流程中的沟通和容易出错的人工操作,高效地达成了设计和实现的一致性。最后,希望本文的内容能给大家带来收获,谢谢。 ---------- END ---------- 百度Geek说 百度官方技术公众号上线啦! 技术干货 · 行业资讯 · 线上沙龙 · 行业大会 招聘信息 · 内推信息 · 技术书籍 · 百度周边 欢迎各位同学关注

优秀的个人博客,低调大师

用AutoCompleteTextView实现历史记录提示

自定义AutoCompleteTextView 博客分类: android进阶 android 网上找到的都是同ArrayAdapter一起使用的,有时候需要自定义风格,咋办?follow me! 看上图,实现了清空输入框内容和删除Item功能。 其实使用AutoCompleteTextView就得实现过滤器Filterable,你得告诉它怎么过滤。由于ArrayAdapter已经 帮我们实现了Filterable接口,所以我们很容易忽略这个,以为AutoCompleteTextView用起来很简单。如果你使用的是 BaseAdapter呢?当然,事实上也不难,只要让它也实现Filterable接口就可以了。 下面是源码: 实现自定义的Adapter Java代码 importjava.util.ArrayList; importjava.util.List; importqianlong.qlmobile.tablet.csco.R; importandroid.content.Context; importandroid.util.Log; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.view.ViewGroup; importandroid.view.View.OnClickListener; importandroid.widget.BaseAdapter; importandroid.widget.Filter; importandroid.widget.Filterable; importandroid.widget.ImageView; importandroid.widget.TextView; publicclassAutoCompleteAdapterextendsBaseAdapterimplementsFilterable{ privateContextcontext; privateArrayFiltermFilter; privateArrayList<String>mOriginalValues;//所有的Item privateList<String>mObjects;//过滤后的item privatefinalObjectmLock=newObject(); privateintmaxMatch=10;//最多显示多少个选项,负数表示全部 publicAutoCompleteAdapter(Contextcontext,ArrayList<String>mOriginalValues,intmaxMatch){ this.context=context; this.mOriginalValues=mOriginalValues; this.maxMatch=maxMatch; } @Override publicFiltergetFilter(){ //TODOAuto-generatedmethodstub if(mFilter==null){ mFilter=newArrayFilter(); } returnmFilter; } privateclassArrayFilterextendsFilter{ @Override protectedFilterResultsperformFiltering(CharSequenceprefix){ //TODOAuto-generatedmethodstub FilterResultsresults=newFilterResults(); //if(mOriginalValues==null){ //synchronized(mLock){ //mOriginalValues=newArrayList<String>(mObjects);// //} //} if(prefix==null||prefix.length()==0){ synchronized(mLock){ Log.i("tag","mOriginalValues.size="+mOriginalValues.size()); ArrayList<String>list=newArrayList<String>(mOriginalValues); results.values=list; results.count=list.size(); returnresults; } }else{ StringprefixString=prefix.toString().toLowerCase(); finalintcount=mOriginalValues.size(); finalArrayList<String>newValues=newArrayList<String>(count); for(inti=0;i<count;i++){ finalStringvalue=mOriginalValues.get(i); finalStringvalueText=value.toLowerCase(); //if(valueText.contains(prefixString)){//匹配所有 // //} //Firstmatchagainstthewhole,non-splittedvalue if(valueText.startsWith(prefixString)){//源码,匹配开头 newValues.add(value); } //else{ //finalString[]words=valueText.split("");//分隔符匹配,效率低 //finalintwordCount=words.length; // //for(intk=0;k<wordCount;k++){ //if(words[k].startsWith(prefixString)){ //newValues.add(value); //break; //} //} //} if(maxMatch>0){//有数量限制 if(newValues.size()>maxMatch-1){//不要太多 break; } } } results.values=newValues; results.count=newValues.size(); } returnresults; } @Override protectedvoidpublishResults(CharSequenceconstraint, FilterResultsresults){ //TODOAuto-generatedmethodstub mObjects=(List<String>)results.values; if(results.count>0){ notifyDataSetChanged(); }else{ notifyDataSetInvalidated(); } } } @Override publicintgetCount(){ //TODOAuto-generatedmethodstub returnmObjects.size(); } @Override publicObjectgetItem(intposition){ //TODOAuto-generatedmethodstub //此方法有误,尽量不要使用 returnmObjects.get(position); } @Override publiclonggetItemId(intposition){ //TODOAuto-generatedmethodstub returnposition; } @Override publicViewgetView(finalintposition,ViewconvertView,ViewGroupparent){ //TODOAuto-generatedmethodstub ViewHolderholder=null; if(convertView==null){ holder=newViewHolder(); LayoutInflaterinflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView=inflater.inflate(R.layout.simple_list_item_for_autocomplete,null); holder.tv=(TextView)convertView.findViewById(R.id.simple_item_0); holder.iv=(ImageView)convertView.findViewById(R.id.simple_item_1); convertView.setTag(holder); }else{ holder=(ViewHolder)convertView.getTag(); } holder.tv.setText(mObjects.get(position)); holder.iv.setOnClickListener(newOnClickListener(){ @Override publicvoidonClick(Viewv){ //TODOAuto-generatedmethodstub Stringobj=mObjects.remove(position); mOriginalValues.remove(obj); notifyDataSetChanged(); } }); returnconvertView; } classViewHolder{ TextViewtv; ImageViewiv; } publicArrayList<String>getAllItems(){ returnmOriginalValues; } } Java代码 importandroid.content.Context; importandroid.util.AttributeSet; importandroid.view.View; importandroid.widget.AutoCompleteTextView; importandroid.widget.ImageView; importandroid.widget.RelativeLayout; importandroid.widget.ImageView.ScaleType; publicclassAdvancedAutoCompleteTextViewextendsRelativeLayout{ privateContextcontext; privateAutoCompleteTextViewtv; publicAdvancedAutoCompleteTextView(Contextcontext){ super(context); //TODOAuto-generatedconstructorstub this.context=context; } publicAdvancedAutoCompleteTextView(Contextcontext,AttributeSetattrs){ super(context,attrs); //TODOAuto-generatedconstructorstub this.context=context; } @Override protectedvoidonFinishInflate(){ super.onFinishInflate(); initViews(); } privatevoidinitViews(){ RelativeLayout.LayoutParamsparams=newRelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,RelativeLayout.LayoutParams.WRAP_CONTENT); tv=newAutoCompleteTextView(context); tv.setLayoutParams(params); tv.setPadding(10,0,40,0); //tv.setSingleLine(true); RelativeLayout.LayoutParamsp=newRelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT); p.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); p.addRule(RelativeLayout.CENTER_VERTICAL); p.rightMargin=10; ImageViewiv=newImageView(context); iv.setLayoutParams(p); iv.setScaleType(ScaleType.FIT_CENTER); iv.setImageResource(R.drawable.delete); iv.setClickable(true); iv.setOnClickListener(newView.OnClickListener(){ @Override publicvoidonClick(Viewv){ //TODOAuto-generatedmethodstub tv.setText(""); } }); this.addView(tv); this.addView(iv); } publicvoidsetAdapter(AutoCompleteAdapteradapter){ tv.setAdapter(adapter); } publicvoidsetThreshold(intthreshold){ tv.setThreshold(threshold); } publicAutoCompleteTextViewgetAutoCompleteTextView(){ returntv; } } simple_list_item_for_autocomplete.xml Xml代码 <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:paddingTop="5dip" android:paddingBottom="5dip" > <TextViewandroid:id="@+id/simple_item_0" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:paddingLeft="5dip" android:textColor="@android:color/black" /> <ImageViewandroid:id="@+id/simple_item_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="fitCenter" android:src="@drawable/delete" android:layout_centerVertical="true" android:layout_marginRight="5dip" /> </LinearLayout> 使用,通常情况下都这样: Java代码 privateAdvancedAutoCompleteTextViewtv; privateAutoCompleteAdapteradapter; privateArrayList<String>mOriginalValues=newArrayList<String>(); @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); mOriginalValues.add("1234561"); mOriginalValues.add("1234562"); mOriginalValues.add("2234563"); mOriginalValues.add("2234564"); mOriginalValues.add("3234561111"); mOriginalValues.add("32345622222"); mOriginalValues.add("323456333333"); mOriginalValues.add("3234564444"); mOriginalValues.add("3234565555"); mOriginalValues.add("32345666666"); mOriginalValues.add("32345777777"); tv=(AdvancedAutoCompleteTextView)findViewById(R.id.tv); tv.setThreshold(0); adapter=newAutoCompleteAdapter(this,mOriginalValues,10); tv.setAdapter(adapter); } 这是arrayAdapter自定义的一个私有内部类,所谓私有,就意味着你不能通过 继承去修改这种过滤方法,同样你也不能直接得到他过滤后结果集results。假如你想使用新的过滤方法,你必须重写getfilter()方法,返回的 filter对象是你要新建的filter对象(在里面包含performFiltering()方法重新构造你要的过滤方法) 2.setDropDownHeight方法 ,用来设置提示下拉框的高度,注意,这只是限制了提示下拉框的高度,提示数据集的个数并没有变化 3.setThreshold方法,设置从输入第几个字符起出现提示 4.setCompletionHint方法,设置提示框最下面显示的文字 5.setOnFocusChangeListener方法,里面包含OnFocusChangeListener监听器,设置焦点改变事件 6.showdropdown方法,让下拉框弹出来 我没有用到的一些方法列举 1.clearListSelection,去除selector样式,只是暂时的去除,当用户再输入时又重新出现 2.dismissDropDown,关闭下拉提示框 3.enoughToFilter,这是一个是否满足过滤条件的方法,sdk建议我们可以重写这个方法 4.getAdapter,得到一个可过滤的列表适配器 5.getDropDownAnchor,得到下拉框的锚计的view的id 6.getDropDownBackground,得到下拉框的背景色 7.setDropDownBackgroundDrawable,设置下拉框的背景色 8.setDropDownBackgroundResource,设置下拉框的背景资源 9.setDropDownVerticalOffset,设置下拉表垂直偏移量,即是list里包含的数据项数目 10.getDropDownVerticalOffset ,得到下拉表垂直偏移量 11..setDropDownHorizontalOffset,设置水平偏移量 12.setDropDownAnimationStyle,设置下拉框的弹出动画 13.getThreshold,得到过滤字符个数 14.setOnItemClickListener,设置下拉框点击事件 15.getListSelection,得到下拉框选中为位置 16.getOnItemClickListener。得到单项点击事件 17.getOnItemSelectedListener得到单项选中事件 18.getAdapter,得到那个设置的适配器一些隐藏方法和构造我没有列举了,具体可以参考api文档 <AutoCompleteTextView android:id="@+id/input_city_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="@string/city_select_hint" android:gravity="center" android:maxLength="5" android:completionThreshold="1" android:popupBackground="@color/stroke_green" android:background="@drawable/edittext_shape"/> 里面的android:popupBackground就是设置下拉框的背景色。 android:completionHint 设置出现在下拉菜单中的提示标题 android:completionThreshold 设置用户至少输入多少个字符才会显示提示 android:dropDownHorizontalOffset 下拉菜单于文本框之间的水平偏移。默认与文本框左对齐 android:dropDownHeight 下拉菜单的高度 android:dropDownWidth 下拉菜单的宽度 android:singleLine 单行显示 android:dropDownVerticalOffset 垂直偏移量 本文转自 一点点征服 博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/5807452.html,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册