首页 文章 精选 留言 我的

精选列表

搜索[企业级UI],共10000篇文章
优秀的个人博客,低调大师

Android优化——UI优化(一)优化布局层次

优化布局层次 1.避免布局镶嵌过深(如下) <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:id="@+id/main_ll_duoyu" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:layout_gravity="center_vertical" > <TextView android:text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> </LinearLayout> </LinearLayout> 我们完全可以去掉id为:main_ll_duoyu的这个LinearLayout,也可以实现我们想要的效果(效果如下) 2.使用工具查看布局 工具路径 sdk\tools\hierarchyviewer.bat | 双击打开 查看布局对比 我们现在去掉了main_ll_duoyu的这个LinearLayout,我们比一下前两张图和最有一张图,中间少了一层,这里只是给举个例子,可以使用google提供的这些工具帮助我们优化app,增加用户体验的流畅性 3.默认最大布局深度 android 默认的对打布局深度为10 本文转自 一点点征服 博客园博客,原文链接: http://www.cnblogs.com/ldq2016/p/5226571.html ,如需转载请自行联系原作者

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

Android UI开发第三篇——popupwindow

PopupWindow在android.widget包下,弹出窗口的形式展示。官方文档对该控件的描述是:“一个弹出窗口控件,可以用来显示任意视图(View),而且会浮动在当前 活动(activity)的顶部”。PopupWindow可以让我们实现多种自定义控件,例如:menu、alertdialog等弹窗似的View。 popupwindow需要在onCreate时初始化、通过触发事件展示出来。 public class ShowPopupWindow extends Activity implements View.OnClickListener{ View view; PopupWindow pop; Button btnShowAsDrawDown; Button btnShowAsDrawDown1; Button btnShowAtLocation; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.popup_activity); btnShowAsDrawDown = (Button)findViewById(R.id.btnShowAsDrawDown); btnShowAsDrawDown.setOnClickListener(this); btnShowAsDrawDown = (Button)findViewById(R.id.btnShowAsDrawDown1); btnShowAsDrawDown.setOnClickListener(this); btnShowAtLocation = (Button)findViewById(R.id.btnShowAt); btnShowAtLocation.setOnClickListener(this); initPopupWindow(); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()) { case R.id.btnShowAsDrawDown: if(pop.isShowing()) { pop.dismiss(); } else { pop.showAsDropDown(v); } break; case R.id.btnShowAsDrawDown1: if(pop.isShowing()) { pop.dismiss(); } else { pop.showAsDropDown(v, 0, -160); } break; default: if(pop.isShowing()) { pop.dismiss(); } else { pop.showAtLocation(findViewById(R.id.main), Gravity.CENTER_HORIZONTAL, 0, 0); } break; } } private void initPopupWindow() { view = this.getLayoutInflater().inflate(R.layout.popup_window, null); pop = new PopupWindow(view, ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); pop.setOutsideTouchable(true); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub pop.dismiss(); } }); } } popup_activity.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:id="@+id/main" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="pop demo!" /> <Button android:id="@+id/btnShowAsDrawDown" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Show as drawndown(one parameter)" /> <Button android:id="@+id/btnShowAsDrawDown1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Show as drawndown(three parameters)" /> <Button android:id="@+id/btnShowAt" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Show At Location" /> </LinearLayout> popup_window.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:gravity="center_horizontal" android:background="#d3d3d3"> <Button android:id="@+id/btn_pop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Close" android:layout_margin="10dip" /> </LinearLayout> 本文转自xyz_lmn51CTO博客,原文链接:http://blog.51cto.com/xyzlmn/817389 ,如需转载请自行联系原作者

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

Appium Android UI自动化简介 + 实战

一、自动化比较适合的场景 1、稳定迭代; 2、回归阶段;回归上一版功能,对新功能不适用。 3、研发驱动的底层代码重构; 不适合case:无网、支付、需要数据准备的case 二、Appium简介 Appium是目前最为强大的自动化测试框架,支持IOS 与Android。 IOS: 苹果公司的 UIAutomation。 Android 4.2+: Google公司的 UiAutomator。 Android 2.3+: Google公司的 Instrumentation. (Instrumentation 的支持是通过绑定另外一个独立的Selendroid项目来实现的)。 C/S 架构 Appium的核心是一个遵守REST设计风格的web 服务器,它接受客户端的连接,接收客户端的命令,在手机设备上执行命令,然后通过HTTP的响应收集命令执行的结果。 支持多语言 三、case编写思路 过程抽象: 定位-------操作-------等待---------校验---------定位 定位方式 1、文案 2、id 3、xpath 4、类名 5、属性 6、组合 PS:元素信息通过UIAutomator Viewer工具查看: 操作 1、点击;2、输入;3、滑动; 等待、判断页面元素出现或者消失: 1、 sleep 2、 View或文案显示 3、 View或文案消失 校验 按需求~文案显示或消失,View显示或消失,Dialog消失或消失,Toast等等 四、操作步骤 1、JDK、Android、eclipse、appium 等环境安装 2、启动appium server端 3、run,举例说明~~ /** * example用例 */ @Test public void test_000_example() { Gotocate(1); Sleep(2000); //文案 driver.findElementByAndroidUIAutomator("new UiSelector().text(\"餐饮\")").click(); Sleep(2000); driver.findElementById("com.baidu.lbs.waimai:id/back").click(); Sleep(2000); //id driver.findElementById("com.baidu.lbs.waimai:id/left_container").click(); Sleep(2000); driver.findElementById("com.baidu.lbs.waimai:id/actionbar_left").click(); Sleep(1000); //xpath driver.findElementByXPath("//android.widget.LinearLayout/android.widget.LinearLayout[1]/android.widget.RelativeLayout[2]").click(); Sleep(2000); driver.findElementById("com.baidu.lbs.waimai:id/back").click(); Sleep(2000); //类名--推荐在View数量小的页面使用 //滑动--下拉 int width = driver.manage().window().getSize().width; int height = driver.manage().window().getSize().height; for(int i = 0; i < 10; i++) { driver.swipe(width / 2, height * 3 / 4, width / 2, height / 4, 1000); } // WaitForStringShow("餐饮"); // WaitForViewShow("com.baidu.lbs.waimai:id/left_container"); // WaitForViewHide("com.baidu.lbs.waimai:id/left_container"); } 五、失败case问题定位 三种可能:1、bug—>提icafe;2、脚本问题->Fix;3、工具问题->寻求其他方式解决;4、环境准备问题(无网、手机无电、有弹窗、目标app后台未杀死等等) 定位问题方式: 1、查看失败case截图 2、定位代码行,查看出错原因(函数级) 3、结合功能,确定出错点 特例:crash,无结果收集,需手工复现

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

iOS_UI进阶【拖拽排序】的实现

导读 拖拽排序是新闻类的App可以说是必有的交互设计,如今日头条,网易新闻等。拖拽排序是一个交互体验非常好的设计,简单,方便。 github地址:https://github.com/HelloYeah/DraggingSort 欢迎Star,予人玫瑰,手有余香。 今日头条的拖拽排序界面 我实现的长按拖拽排序效果 实现方案 1.给CollectionViewCell添加一个长按手势,通过协议把手势传递到collectionView所在的控制器中。 - (void)awakeFromNib{ self.layer.cornerRadius = 3; self.layer.masksToBounds = YES; //给每个cell添加一个长按手势 UILongPressGestureRecognizer * longPress =[[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)]; longPress.delegate = self; [self addGestureRecognizer:longPress]; } - (void)longPress:(UILongPressGestureRecognizer *)longPress{ if (self.delegate && [self.delegate respondsToSelector:@selector(longPress:)]) { [self.delegate longPress:longPress]; } } 2.开始长按时对cell进行截图,并隐藏cell。 - (void)longPress:(UILongPressGestureRecognizer *)longPress{ //记录上一次手势的位置 static CGPoint startPoint; //触发长按手势的cell MovingCell * cell = (MovingCell *)longPress.view; //开始长按 if (longPress.state == UIGestureRecognizerStateBegan) { [self shakeAllCell]; //获取cell的截图 _snapshotView = [cell snapshotViewAfterScreenUpdates:YES]; _snapshotView.center = cell.center; [_collectionView addSubview:_snapshotView]; _indexPath= [_collectionView indexPathForCell:cell]; _originalCell = cell; _originalCell.hidden = YES; startPoint = [longPress locationInView:_collectionView]; } 3、在手势移动的时候,移动截图视图,用遍历的方法求出截图移动到哪个cell的位置,再调用系统的api交换这个cell和隐藏cell的位置,并且数据源中的数据也需要调整顺序 //手势移动的时候 else if (longPress.state == UIGestureRecognizerStateChanged){ CGFloat tranX = [longPress locationOfTouch:0 inView:_collectionView].x - startPoint.x; CGFloat tranY = [longPress locationOfTouch:0 inView:_collectionView].y - startPoint.y; //设置截图视图位置 _snapshotView.center = CGPointApplyAffineTransform(_snapshotView.center, CGAffineTransformMakeTranslation(tranX, tranY)); startPoint = [longPress locationOfTouch:0 inView:_collectionView]; //计算截图视图和哪个cell相交 for (UICollectionViewCell *cell in [_collectionView visibleCells]) { //跳过隐藏的cell if ([_collectionView indexPathForCell:cell] == _indexPath) { continue; } //计算中心距 CGFloat space = sqrtf(pow(_snapshotView.center.x - cell.center.x, 2) + powf(_snapshotView.center.y - cell.center.y, 2)); //如果相交一半且两个视图Y的绝对值小于高度的一半就移动 if (space <= _snapshotView.bounds.size.width * 0.5 && (fabs(_snapshotView.center.y - cell.center.y) <= _snapshotView.bounds.size.height * 0.5)) { _nextIndexPath = [_collectionView indexPathForCell:cell]; if (_nextIndexPath.item > _indexPath.item) { for (NSUInteger i = _indexPath.item; i < _nextIndexPath.item ; i ++) { [self.array exchangeObjectAtIndex:i withObjectAtIndex:i + 1]; } }else{ for (NSUInteger i = _indexPath.item; i > _nextIndexPath.item ; i --) { [self.array exchangeObjectAtIndex:i withObjectAtIndex:i - 1]; } } //移动 [_collectionView moveItemAtIndexPath:_indexPath toIndexPath:_nextIndexPath]; //设置移动后的起始indexPath _indexPath = _nextIndexPath; break; } } 4.手势停止时,移除截图的view,显示隐藏cell //手势停止时 }else if(longPress.state == UIGestureRecognizerStateEnded){ [self stopShake]; [_snapshotView removeFromSuperview]; _originalCell.hidden = NO; } 其他 代码还可以进一步封装,写一个数据管理类dataTool,dataTool作为collectionView的数据源,所有的数据源方法都写到dataTool类中。手势的代理方法也在里面实现,这样控制器会简洁很多,控制器就不需要关注拖拽排序的具体逻辑了。大家有空可以自己写写看,也许你们有更好的处理方案,可以评论交流一下。 github地址:https://github.com/HelloYeah/DraggingSort 提示 如果你们是从iOS9开始适配的话,那么可以用系统的Api,非常简单好用 //是否允许拖拽 - (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0); /** * 从sourceIndexPath 拖拽至destinationIndexPath,在这个代理方法里修改数据源即可。 * exchangeObjectAtIndex:sourceIndexPath.item withObjectAtIndex: destinationIndexPath.item */ - (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath NS_AVAILABLE_IOS(9_0);

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

Springboot企业级部署解决方案

使用springboot的童鞋们,有没曾经想把项目打包成 bin/conf/libs/logs 等这样的结构然后直接运行的,但是找了很多办法都不够完美(因为G是个完美主义 ) 好了直接来看解决方案: 1、修改执行打包的子工程的pom.xml文件(加入两个插件): <build> <finalName>app</finalName> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> <excludes> <exclude>script/**</exclude> </excludes> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.1</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.6</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <skip>true</skip> <archive> <manifest> <mainClass>com.xxx.bbb.MyMainClass</mainClass> <addClasspath>true</addClasspath> </manifest> <manifestEntries> <Class-Path>./</Class-Path> <Built-By>Wangl.sir</Built-By> <Built-Mail-By>983708408@qq.com</Built-Mail-By> <Bundle-Name>Project Description</Bundle-Name> <Implementation-Vendor></Implementation-Vendor> <Implementation-URL>http://www.xxx.com/wiki</Implementation-URL> </manifestEntries> </archive> </configuration> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <finalName>app-${project.version}-bin</finalName> <!-- not append assembly id in release file name --> <appendAssemblyId>false</appendAssemblyId> <descriptors> <descriptor>src/main/assemble/package.xml</descriptor> </descriptors> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build> 2、新增assemble配置文件(保存至src/main/assemble/package.xml): <assembly xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/assembly-1.0.0.xsd"> <id>jar-with-dependencies</id> <formats> <format>zip</format> </formats> <includeBaseDirectory>true</includeBaseDirectory> <fileSets> <fileSet> <!-- src/main/resources/script目录保存的如:app_ctrl.sh、app_start.sh、app_stop.sh等脚本,maven-assemble会将此目录下的.sh文件复制到最后生成的bin目录下 --> <directory>src/main/resources/script</directory> <outputDirectory>bin</outputDirectory> <includes> <include>*.*</include> </includes> </fileSet> <fileSet> <directory>src/main/resources</directory> <outputDirectory>conf</outputDirectory> <includes> <include>*.*</include> </includes> </fileSet> <fileSet> <directory>target</directory> <outputDirectory>libs</outputDirectory> <includes> <include>*.jar</include> </includes> </fileSet> <fileSet> <directory>src/main/resources</directory> <outputDirectory>logs</outputDirectory> <excludes> <exclude>*.*</exclude> <exclude>script/**</exclude> </excludes> </fileSet> </fileSets> <dependencySets> <dependencySet> <outputDirectory>libs</outputDirectory> <scope>runtime</scope> <excludes> <exclude>${groupId}:${artifactId}</exclude> </excludes> </dependencySet> </dependencySets> </assembly> 3、最后就只需执行 mvn clean install -DskipTests 等待maven执行完成,在target目录下会出现app-{project.version}-bin.zip

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

企业级网络监控系统“必备技能”

网络可用性监控系统通常是应用程序出现故障时的第一道防线。IT组织的各个团队免不了在出事时互相推委责任,这时网络可用性监控系统就是一个必不可少的工具。 事实上,只要部署了正确的系统,这种推卸责任的现象甚至都不可能再出现。这种可用性监控工具有完备的警报和错误隔离功能。拥有这种工具,网络团队就可以提前处理服务问题。 网络可用性监控系统市场中有各种各样的产品,既有只支持有限功能和规模的开源工具,也有来自IBM和惠普等大型企业IT管理供应商的大型企业产品。在购买监控系统时,采购团队必须将企业需求与各种产品的网络监控特性。 在收集供应商的征询方案(RFP)时,有几点是必须考虑的:方便部署、可用性、兼容现有基础架构、可扩展性及与大量IT管理工具的集成支持。 部署模式 在考虑网络可用性监控系统的部署方式时,第一个问题是了解清楚授权模式。不同供应商的授权方式大相径庭。有一些按照不同的监控功能来销售许可证,而其他一些则按照企业需要管理的设备或逻辑对象的数量来收费。一定要仔细检查他们的授权方式,以确定系统的使用成本及维护难度。 下一个要注意的问题是实际部署模式。采购团队应该弄清楚供应商是否提供了关于系统配置的最佳实践指导。此外,有一些监控系统是独立部署的软件包,而另一些则要求单独安装各个组件,其中包括数据库、检测系统、分析引擎和前端控制台。通常,如果供应商的产品部署中包含多个组件,那么就会采用后一种部署方式,以实现最大的可扩展性和灵活性,但是这种方法也会给某些企业增加额外的复杂性。 易用性 采购团队应该确保网络可用性监控系统的现有需求能够保证所选择的系统能够高效地运行。但是现实并非总是如此。企业管理协会的研究表明,企业中存在大量中看不中用的存架软件——即一些耗费时间且成本昂贵的工具软件。 管理控制台是网络人员要评估的一个最重要的网络监控系统特性。系统上是否有面向典型用户的合理图表功能?命令是否足够简单?相关人员需要经过多少的培训才能学会使用系统?在这种情况下,通过一次概念验证过程,让网络管理人员真实地体验这个系统,能够帮助保证系统的顺利使用并为企业产生价值。 兼容现有网络基础架构 许多组织都在企业环境中混合使用多种供应商的产品。例如,他们可能会使用一两家供应商的交换机,然后再使用另一家的边界路由器。而且,可能还会使用另一家供应商的无线设备。在评估网络可用性监控系统时,风格团队需要确定该工具支持哪一些供应商和平台。 这个评估过程可能需要扩大到网络基础架构之外。许多企业还会监控这些系统连接的服务器和存储。在检查一个管理系统所支持的供应商和设备时,采购团队还必须界定它能够管理的技术类型。这其中包括虚拟化技术和云服务。 系统可扩展性 网络可用性监控系统可能会由于所能管理的风格规模不同而大相径庭。有一些供应商的产品能够监控上百个设备,而其他供应商的产品则能够监控成千上万个设备。而且,有一些系统只能够监控一个位置,但是其他产品则可以覆盖整个企业。 一定要确定网络监控系统所能支持的最大规模和分布程度,而且更重要的是要确定供应商实现可扩展性的方式。某一个供应商可能能够在一台服务器上监控一个包含成千上万台设备的大型分布式网络。而其他供应商则可能将多个服务器部署到企业各个位置,然后通过一个前端控制台将它们绑定在一起。这些差别都将影响系统的使用方式和复杂程度。 互操作性 和其他产品类似,这种网络监控系统也属于大型IT管理系统的一部分。采购团队应该评估企业是否需要集成其他的管理产品。例如,网络工程团队可能会使用可用性监控系统去监控和管理网络,而网络运营团队则可能会使用更高级的服务保证系统。这两种系统之间的集成将促进不同团队之间的协作。 其他潜在的网络监控系统特性还包括网络性能管理、日志分析、应用性能管理、网络变更与配置管理等等。事实上,许多网络可用性监控供应商都提供了大量的IT管理工具及其不同程度的集成技术。然而,对于第三方平台的集成,采购团队还应该评估供应商的技术合作伙伴生态系统、认证类型及这些集成技术附带的联合支持。 总结 前面提到的每一个网络监控系统特性构成了RFP的主体部分,它们是可用性监控系统的采购依据。市场中有大量不同形态的产品,而且许多供应商往往言过其实。因此网络团队一定要全面理解监控系统的需求,再将这些需求与所评估产品的功能相关联。采购团队应该回答所有这些问题,并且在产品评估过程中验证这些问题,然后才能够作出采购决策。 作者:Shamus McGillicuddy 翻译:曾少宁 来源:51CTO

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

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

Sublime Text

Sublime Text

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册