辰迅云帮助中心

其他类

RPC服务与HTTP服务的区别是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1、什么是RPCRPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。RPC采用客户机/服务器(c/s)模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。2、OSI网络七层模型在说RPC和HTTP的区别之前,我觉的有必要了解一下OSI的七层网络结构模型,它可以分为以下几层(自下而上):第一层:物理层。这一层主要就是传输这些二进制数据。第二层:链路层。将上面的网络层的数据包封装成数据帧,便于物理层传输;第三层:网络层。定义网络设备间如何传输数据;第四层:传输层。管理着网络中的端到端的数据传输;第五层:会话层。管理用户的会话,控制用户间逻辑连接的建立和中断;第六层:表示层。定义不同的系统中数据的传输格式,编码和解码规范等;第七层:应用层。定义了用于在网络中进行通信和传输数据的接口;3、RPC调用流程简单地说一下,一个完整的RPC架构里面包含了四个核心的组件,分别是Client ,Server,Client Stub以及Server Stub1、 客户端(RPC Client):服务调用方2、 客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数打包成网络消息,再通过网络发送给服务方3、 服务端存根(Server Stub):接受客户端发送过来的消息并解包,再调用本地服务4、 服务端(RPC Server):真正的服务提供者。RPC采用C/S模式,请求程序就是一个客户端应用,而服务提供者就是一个服务器。首先,服务消费者(RPC客户端应用)调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务提供方(RPC服务器端),进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,调用服务端方法对调用请求进行计算而得到计算结果,并发送答复信息,然后等待下一个调用信息;最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。4、RPC架构的作用RPC 的主要目标是让构建分布式计算(应用)更容易、透明,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC 框架需提供一种透明调用机制让使用者不必显式的区分本地调用和远程调用。RPC框架负责屏蔽底层的传输方式(TCP或者UDP)、序列化方式(XML/JSON/二进制)和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。5、常见RPC技术和框架(1)、应用级的服务框架:阿里的Dubbo/Dubbox、Google GRPC、Spring Boot/Spring Cloud。(2)、远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)。(3)、通信框架:MINA和Netty6、HTTP服务 VS RPC服务传输协议RPC,可以基于TCP协议,也可以基于HTTP协议HTTP,基于HTTP协议传输效率RPC,使用自定义的TCP协议,可以让请求报文体积更小,或者使用HTTP2协议,也可以很好的减少报文的体积,提高传输效率HTTP,如果是基于HTTP1.1的协议,请求中会包含很多无用的内容,如果是基于HTTP2.0,那么简单的封装以下是可以作为一个RPC来使用的,这时标准RPC框架更多的是服务治理性能消耗,主要在于序列化和反序列化的耗时RPC,可以基于thrift实现高效的二进制传输HTTP,大部分是通过json来实现的,字节大小和序列化耗时都比thrift要更消耗性能负载均衡RPC,基本都自带了负载均衡策略HTTP,需要配置Nginx,HAProxy来实现服务治理(下游服务新增,重启,下线时如何不影响上游调用者)RPC,能做到自动通知,不影响上游HTTP,需要事先通知,修改Nginx/HAProxy配置看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注辰讯云资讯频道,感谢您对辰讯云的支持。...

HashMap和Hashtable有什么不同,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。线程安全两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全。Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,我们平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合(Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步,类似的其它Collections.synchronizedXX方法也是类似原理。NULL值HashMap可以使用null作为key,不过建议还是尽量避免这样使用。HashMap以null作为key时,总是存储在table数组的第一个节点上。当get()方法返回null 值时,既可以表示HashMap 中没有该键,也可以表示该键所对应的值为null。因此,在HashMap 中不能用get()方法来判断HashMap 中是否存在某个键,而应该用containsKey()方法来判断。而Hashtable则不允许null作为key。继承关系HashMap继承了AbstractMap,HashTable继承Dictionary抽象类,两者均实现Map接口。容量初始值HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。扩容方式HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1。底层结构HashMap和Hashtable的底层实现都是数组+链表结构实现。哈希算法Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模:    int hash = key.hashCode();    int index = (hash & 0x7FFFFFFF) % tab.length; HashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度取摸:    static int hash(int h) {         h ^= (h >>> 20) ^ (h >>> 12);         return h ^ (h >>> 7) ^ (h >>> 4);     }    static int indexFor(int h, int length) {         return h & (length-1);     }看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注辰讯云资讯频道,感谢您对辰讯云的支持。...

这期内容当中小编将会给大家带来有关mybatis中怎么利用注解对对象进行批量更改,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。mybatis注解对象批量更改一、介绍当有多个对象需要进行更改时,批量修改对象集合List二、代码@Update("<script>"+ "<foreach collection='listUserAnswerRecord' item='item' open='' close=''  separator=';'> "+ " update t_qb_record_201910"+ " set answered = 0, progress = 1, answer_sheet = null, gmt_update = #{item.gmtUpdate}"+ " <where>"+ "<choose>"+ "<when test='item.unionid !=null'> unionid=#{item.unionid}</when>"+ "<otherwise> openid= #{item.openid} </otherwise>"+ "</choose>"+ " and goods_id = #{item.goodsId} and charpter_id = #{item.charpterId} and type = #{item.type}"+ "</where>"+ "</foreach>"+ "</script>") Integer deleteUserAnswerSheet(@Param("listUserAnswerRecord") List<UserAnswerRecordNew> listUserAnswerRecord);mybatis 注解批量更新、插入//批量插入 @Insert({         "<script>",         "insert into table(column1, column2) values ",         "<foreach collection='userLists' item='item' index='index' separator=','>",         "(#{item.column1}, #{item.column2} )",         "</foreach>",         "</script>" }) public int insertUsers(@Param(value="userLists") List<User> userLists);//批量更新@Update({ "<script>", "<foreach collection='userLists' item='item' index='index' separator=';'>", "update table b", "set b.column1= #{item.column1},b.column2= #{item.column2}  where b.column3= #{item.column3}", "</foreach>", "</script>"    })     public int updateUser(@Param(value="userLists") List<User> userLists);collection:你传来的集合item:里面的类index:就是for循环的iseparator:间隔符上述就是小编为大家分享的mybatis中怎么利用注解对对象进行批量更改了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注辰讯云资讯频道。...

这期内容当中小编将会给大家带来有关Java中怎么处理异常类型,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、异常的描述程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常。异常发生时,是任程序自生自灭,立刻退出终止。在Java中即,Java在编译或运行或者运行过程中出现的错误。Java提供了更加优秀的解决办法:异常处理机制。异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。Java中的异常可以是函数中的语句执行时引发的,也可以是程序员通过throw 语句手动抛出的,只要在Java程序中产生了异常,就会用一个对应类型的异常对象来封装异常,JRE就会试图寻找异常处理程序来处理异常。异常指在运行时期发生的不正常情况。在java中用类的形式对不正常情况进行了描述和封装对象。描述不正常情况的类,就成为异常类。将正常代码和问题处理代码分离,提高阅读性。其实异常就是java通过面向对象的思想将问题封装成了对象,用异常类对其进行描述。二、异常的体系两大类:hrowable:可抛出的异常,无论是error还是exception,问题发生就应该可以抛出,让调用者知道并且处理。该体系的特点就是在于Throwable及其所有的子类都具有可抛性。可抛性到底指的是什么?怎么体现可抛性呢?通过两个关键字来体现的。throws throw 凡是可以被这两个关键字所操作的类和对象都具有可抛性。子类1  一般不可处理的。————Error特点:是由jvm抛出的严重性问题,这种问题发生一般不针对性处理,直接修改程序。子类2)可以处理的。————Exception,问题抛给调用者,谁用抛给谁。特点:子类后缀名都是用其父类名作为后缀名,阅读性很强!范例:比如自定义一个负数角标的异常,使用面向对象思想封装成对象。注意:如果让一个类称为异常类,必须要继承异常类。因为只有异常体系的子类才具有可抛性。class FuShuIndex extends Exception{                 //构造函数 和类名一样                FuShuIndex(){                   }                 //定义一个带参数的构造函数                FuShuIndex(String msg){                     //调用Exception中的带参数异常函数                    super(msg);                   }             }             主函数 throws FuShuIndex:{                int[] arr = new int[3];                method(arr,-7);             }             public static int method(int[] arr,int index) throws arrIndexexception {                  if (index<0){                     throw new arrIndexexception("数组的角标不能为负数");                  }                 return arr[index];             }三、异常的分类:编译时被检测异常还要是Exception和其子类都是,除了特殊子类RuntimeException体系未处理即编译失败!这种问题一旦出现,希望在编译时就进行检测,让这种问题有相应的处理方式,这样的问题都可以针对性处理。编译时不被检测异常(运行时异常):RuntimeException和其子类可处理可不处理,编译都可以通过,运行时会检测!这种问题的发生,无法让功能继续,运算无法运行,更多因为调用的原因导致,或者引发了内部状态的改变导致的。这种问题一般不处理,直接编译通过,在运行时,让调用者时程序强制停止,让调用者对代码进行修正。throws和throw的区别:throws使用在函数上  ————申明throw使用在函数内,可以抛出多个,用逗号隔开。 ————抛出throws抛出的是异常类,可以抛出多个。throw抛出的是异常对象。四、异常处理的捕捉形式这是可以对异常进行针对性处理的方式。格式:try{             //需要被检测异常的代码        }         catch(异常类 变量)//该变量用于接收发生的异常对象{            //处理异常代码        }         finally{             //一定会被执行的代码      }范例class FuShuIndex extends Exception{             //构造函数 和类名一样            FuShuIndex(){               }             //定义一个带参数的构造函数            FuShuIndex(String msg){                 //调用Exception中的带参数异常函数                super(msg);               }   }主函数:无需throws抛出,下面我们自己捕获异常{            int[] arr = new int[3];            try{            method(arr,-7);            }catch(arrIndexexception a){                 a.printStackTrace();//jvm默认的异常处理机制就是调用异常对象的这个方法。                System.out.println("数组的角标异常!!!");//自定义捕获后打印的信息                System.out.println(a.toString());//打印该异常对象的信息                System.out.println(a.getMessage());//获取我们自定义抛出所定义的信息                }   }public static int method(int[] arr,int index) throws arrIndexexception {              if (index<0){                 throw new arrIndexexception("数组的角标不能为负数");              }             return arr[index];  }一个try对应多个catch:多catch情况下,父类的catch要放在最下面,否则编译为空。五、异常处理的原则函数内部如果抛出了需要检测的异常,那么函数上必须申明,或者必须在函数内用try catch捕捉,否则编译失败。如果调用到了申明异常的函数,要么try catch 或者 throws ,否则编译失败。什么时候catch?什么时候throws?功能内容可以解决,用catch。解决不了,用throws告诉调用者,由调用者解决。一个功能如果抛出了多个异常,那么调用时,必须有对应的多个catch来进行针对性处理。内部有几个需要检测的异常,就抛几个异常,抛出几个就catch几个异常。六、finally通常用于关闭(释放)资源。必须要执行。除非jvm虚拟机挂了。范例:出门玩,必须关门,所以将关门这个动作放在finally里面,必须执行。凡是涉及到关闭连接等操作,要用finally代码块来释放资源。try catch finally 代码块组合特点:try catch finally:当有资源需要释放时,可以定义finallytry catch(多个):当没有资源需要释放时,可以不定义finallytry finally:异常处理不处理我不管,但是我得关闭资源,因为资源是我开的,得在内部关掉资源。范例:try{                     //连接数据库                }                     //没有catch意思不处理异常,只单纯的捕获异常                finally{                     //关闭连接                }七、异常的应用老师用电脑讲课范例:电脑类:public class Computer {                 private int state = 2;                 public void run() throws lanpingExcption,maoyanExcption{                     if (state == 1){                         throw new lanpingExcption("电脑蓝屏啦~");                     }else if (state == 2){                         throw new maoyanExcption("电脑冒烟啦~");                     }                     System.out.println("电脑启动");                 }                 public void chongqi(){                     state = 0;                     System.out.println("重启电脑!");                 }   }老师类:public class Teacher {             private String name;             private Computer computer;             Teacher(String name){                 this.name = name;                 computer = new Computer();             }             void teach() throws maoyanExcption{                 try {                     computer.run();                     System.out.println(this.name + "开始用电脑讲课了");                 } catch (lanpingExcption l) {                     l.printStackTrace();                     computer.chongqi();                     teach();//重启后再次讲课                } catch (maoyanExcption m) {                     m.printStackTrace();                     test();                     throw m;                 }             }             public void test(){                 System.out.println("大家自己练习去~");             }   }蓝屏异常类:public class lanpingExcption extends Exception{             lanpingExcption (String msg){                  super(msg);             }  }冒烟异常类:public class maoyanExcption extends Exception {             maoyanExcption (String msg){                 super(msg);             } }主函数:public class Testmain {             public static void main (String[] args){                 Teacher teacher = new Teacher("丁老师");                 try {                     teacher.teach();                 } catch (maoyanExcption m) {                     //m.printStackTrace();                    System.out.println("。。。。。");                 }             }     }八、异常的注意事项:子类在覆盖父类方法时,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类。如果父类抛出多个异常,那么子类只能抛出父类异常的子集。子类覆盖父类,只能抛出父类的异常或者子类。如果父类的方法没有抛出异常,子类覆盖时绝对不能抛。上述就是小编为大家分享的Java中怎么处理异常类型了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注辰讯云资讯频道。...

这篇文章主要介绍“怎么在 Linux 上创建一个加密文件保险库”,在日常操作中,相信很多人在怎么在 Linux 上创建一个加密文件保险库问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么在 Linux 上创建一个加密文件保险库”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!1、建立一个空文件首先,你必须创建一个预定大小的空文件。就像是一种保险库或保险箱,你可以在其中存储其他文件。你使用的命令是 util-linux 软件包中的 fallocate:$ fallocate --length 512M vaultfile.img这个例子创建了一个 512MB 的文件,但你可以把你的文件做成任何你想要的大小。2、创建一个 LUKS 卷接下来,在空文件中创建一个 LUKS 卷:$ cryptsetup --verify-passphrase \    luksFormat vaultfile.img3、打开 LUKS 卷要想创建一个可以存储文件的文件系统,必须先打开 LUKS 卷,并将其挂载到电脑上:$ sudo cryptsetup open \    --type luks vaultfile.img myvault$ ls /dev/mappermyvault4、建立一个文件系统在你打开的保险库中建立一个文件系统:$ sudo mkfs.ext4 -L myvault /dev/mapper/myvault如果你现在不需要它做什么,你可以关闭它:$ sudo cryptsetup close myvault5、开始使用你的加密保险库现在一切都设置好了,你可以在任何需要存储或访问私人数据的时候使用你的加密文件库。要访问你的保险库,必须将其挂载为一个可用的文件系统:$ sudo cryptsetup open \    --type luks vaultfile.img myvault$ ls /dev/mappermyvault$ sudo mkdir /myvault$ sudo mount /dev/mapper/myvault /myvault这个例子用 cryptsetup 打开保险库,然后把保险库从 /dev/mapper 下挂载到一个叫 /myvault 的新目录。和 Linux 上的任何卷一样,你可以把 LUKS 卷挂载到任何你想挂载的地方,所以除了 /myvault,你可以用 /mnt 或 ~/myvault 或任何你喜欢的位置。当它被挂载后,你的 LUKS 卷就会被解密。你可以像读取和写入文件一样读取和写入它,就像它是一个物理驱动器一样。当使用完你的加密保险库时,请卸载并关闭它:$ sudo umount /myvault$ sudo cryptsetup close myvault加密的文件保险库你用 LUKS 加密的镜像文件和其他文件一样,都是可移动的,因此你可以将你的保险库存储在硬盘、外置硬盘,甚至是互联网上。只要你可以使用 LUKS,就可以解密、挂载和使用它来保证你的数据安全。轻松加密,提高数据安全性,不妨一试。到此,关于“怎么在 Linux 上创建一个加密文件保险库”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注辰讯云网站,小编会继续努力为大家带来更多实用的文章!...

小编给大家分享一下IOS如何实现手机震动的提示功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!IOS开发实现手机震动的提示实例代码我们都知道手机有震动功能,其实呢,这个功能实现起来特别的简单,我们只需要用到几个函数就可以了:  - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event还有就是通过canBecomeFirstResponder:设置一个第一响应者为label,然后摇动手机两下,看看效果如下:代码如下:HHLAppDelegate.h#import <UIKit/UIKit.h>  @class HHLViewController;  @interface HHLAppDelegate : UIResponder <UIApplicationDelegate>  @property (strong, nonatomic) UIWindow *window;   @property (strong, nonatomic) HHLViewController *viewController;   @endHHLAppDelegate.m#import "HHLAppDelegate.h"  #import "HHLViewController.h"  @implementation HHLAppDelegate   - (void)dealloc  {    [_window release];    [_viewController release];    [super dealloc];  }    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  {    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];    // Override point for customization after application launch.   self.viewController = [[[HHLViewController alloc] initWithNibName:@"HHLViewController" bundle:nil] autorelease];    self.window.rootViewController = self.viewController;    [self.window makeKeyAndVisible];    return YES;  }    - (void)applicationWillResignActive:(UIApplication *)application  {    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.   // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. }    - (void)applicationDidEnterBackground:(UIApplication *)application  {    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. }    - (void)applicationWillEnterForeground:(UIApplication *)application  {    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. }    - (void)applicationDidBecomeActive:(UIApplication *)application  {    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. }    - (void)applicationWillTerminate:(UIApplication *)application  {    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. }   @endHHLViewController.h#import <UIKit/UIKit.h>  @interface HHLViewController : UIViewController  @end     @interface LabelForMotion : UILabel  @endHHLViewController.m#import "HHLViewController.h"  @interface HHLViewController ()  @end       @implementation LabelForMotion   - (BOOL)canBecomeFirstResponder  {    return YES;  }   @end @implementation HHLViewController   - (void)viewDidLoad  {    [super viewDidLoad];    LabelForMotion *label = [[[LabelForMotion alloc]init]autorelease];    label.frame = self.view.bounds;    label.autoresizingMask =UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;    label.textAlignment = NSTextAlignmentCenter;        label.text = @"Shake me";    [self.view addSubview:label];    //将标签设置为第一响应者   [label becomeFirstResponder];    [label release];  }      - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event  {    NSLog(@"motionBegan");  }   //震动结束时调用的方法 - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event  {    NSLog(@"motionEnded");    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:nil message:@"地震了" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil nil];    [alert show];    [alert release];      }  - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event  {    NSLog(@"motionCancelled");  }      - (void)didReceiveMemoryWarning  {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated. }   @end其实更简单的没有必要搞一个类继承自UIlabel,可以直接定义一个UIlabel的对象就行了。以上是“IOS如何实现手机震动的提示功能”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

这篇文章给大家分享的是有关iOS中如何仿QQ实现侧滑菜单功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。UITabBarController做QQ侧滑菜单效果:首先要了解UITabBarController的层级结构:UITabBarController加载的其它UIViewController的View都是被添加在UITransitionView上(这是一个私有API),UITransitionView在self.view的0层,UITabBar在的第一层。所以我的思路是这样的:UITransitionView与UITabBar转移到一个新的View1上去,作为滑动的部分;在View1与self.view之间再添加一个View2,作为菜单的容器;给View1添加相应的手势响应;代码:#import <UIKit/UIKit.h>@protocol SlideTab_VC_TCVDelegate <NSObject>@optional-(void)didOpenMenu:(UIView*)menu; -(void)didCloseMenu:(UIView*)menu;@end@interface SlideTab_VC : UITabBarController@property(strong, nonatomic)UIView *mMenuV;@property(weak, nonatomic)id <SlideTab_VC_TCVDelegate> mDelegate; -(void)openMenu; -(void)closeMenu;@end#import "SlideTab_VC.h"#define DEVICE_W [UIScreen mainScreen].bounds.size.width@interface SlideTab_VC ()<UITabBarDelegate>{  CGFloat _centerMaxX; }@property(strong, nonatomic)UIView *mTransitionView;@property(strong, nonatomic)UITapGestureRecognizer *mTapGester;@property(assign, nonatomic)BOOL mMenuIsOpen;@property(strong, nonatomic)UITabBar *mTabBar;@end@implementation SlideTab_VC- (void)viewDidLoad {  [super viewDidLoad];  // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor purpleColor];  _mMenuIsOpen = NO;  _centerMaxX = DEVICE_W*3/2-80.0f;  [self initMTransitionView];  [self addGestureForMTransitionView]; }#pragma mark 菜单懒加载-(void)setMMenuV:(UIView *)mMenuV{  if (mMenuV!=nil) {   _mMenuV = mMenuV;   [self.view insertSubview:_mMenuV atIndex:0];  } }#pragma mark 打开菜单-(void)openMenu{  CGPoint center = self.mTransitionView.center;  center.x = _centerMaxX;  [UIView animateWithDuration:0.15f animations:^{   self.mTransitionView.center = center;   if (_mDelegate != nil&& [_mDelegate respondsToSelector:@selector(didOpenMenu:)]) {   [_mDelegate didOpenMenu:_mMenuV];  }  }];  [self mTransitionSubViewsEnable:NO]; }#pragma mark 关闭菜单-(void)closeMenu{  CGPoint center = self.mTransitionView.center;  center.x = DEVICE_W/2;  [UIView animateWithDuration:0.15f animations:^{   self.mTransitionView.center = center;  } completion:^(BOOL finished) {   [self mTransitionSubViewsEnable:YES];   if (_mDelegate != nil&& [_mDelegate respondsToSelector:@selector(didCloseMenu:)]) {   [_mDelegate didCloseMenu:_mMenuV];  }  }]; }#pragma mark Transition用户交互使能-(void)mTransitionSubViewsEnable:(BOOL)enable{  for (UIView *tmp in self.mTransitionView.subviews) {   tmp.userInteractionEnabled = enable;  }  if (enable) {   [self.mTransitionView removeGestureRecognizer:_mTapGester];  }else{   [self.mTransitionView addGestureRecognizer:_mTapGester];  } }#pragma mark 配置mTransitionView-(void)initMTransitionView{  for (UIView *tmp in self.view.subviews) {   [tmp removeFromSuperview];   [self.mTransitionView addSubview:tmp];  }  [self.view addSubview:self.mTransitionView]; }#pragma mark 拖动手势动作-(void)panAction:(UIPanGestureRecognizer*)pan{  CGPoint location = [pan translationInView:pan.view.superview];  CGPoint center = self.mTransitionView.center;  if (pan.state==UIGestureRecognizerStateEnded) {   if (center.x<_centerMaxX*0.5+DEVICE_W*0.25){    [self closeMenu];   }else{    [self openMenu];   }  }else if(pan.state==UIGestureRecognizerStateChanged){   if (location.x<0) {//向左滑   center.x = center.x+location.x<=DEVICE_W/2? DEVICE_W/2 : center.x+location.x;   }else{    center.x = center.x+location.x>=_centerMaxX? _centerMaxX : center.x+location.x;   }   self.mTransitionView.center = center;   [pan setTranslation:CGPointMake(0, 0) inView:pan.view.superview];  } }#pragma mark 添加手势-(void)addGestureForMTransitionView{  UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panAction:)];  [_mTransitionView addGestureRecognizer:pan];  _mTapGester = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapAction)]; }#pragma mark--懒加载-(UIView *)mTransitionView{  if (_mTransitionView==nil) {   _mTransitionView = [[UIView alloc]initWithFrame:self.view.bounds];  }  return _mTransitionView; } -(void)tapAction{  CGFloat x = _mTransitionView.center.x;  if (x>=_centerMaxX) {   [self closeMenu];  } }@end感谢各位的阅读!关于“iOS中如何仿QQ实现侧滑菜单功能”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!...

iOS中标签Tag列表怎么用

2021/7/8 23:38:30

这篇文章主要介绍了iOS中标签Tag列表怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言1、之前项目中会有一些标签列表来显示某些特性或要求,如下图(代码实现后的效果):2、期间也是浏览了好多其他的第三方,但是可能是没找到好的方法去寻找吧,没有找到一个合适的,况且又不是特别复杂的东西,所以就自己写了一套,但是注意因为我们项目中使用的是RAC+Mansory,所以想要使用的话需要引入这两个库=_=。3、自己写的时候考虑的不是太多,中心思想是ViewModel做定制需求,View通过ViewModel来实现定制化UI,其他更多的是逻辑上的排版,所以不做更多赘述,自己体会Y^o^Y 。View布局LSLabelTextView.h的实现//// LSLabelTextView.h// RenCheRen//// Created by 王隆帅 on 15/12/30.// Copyright &copy; 2015年 王隆帅. All rights reserved.//#import "YCView.h"@interface LSLabelTextView : YCView@endLSLabelTextView.m的实现//// LSLabelTextView.m// RenCheRen//// Created by 王隆帅 on 15/12/30.// Copyright &copy; 2015年 王隆帅. All rights reserved.//#import "LSLabelTextView.h"#import "LSLabelTextViewModel.h"@interface LSLabelTextView ()@property (nonatomic, strong) LSLabelTextViewModel *viewModel;@end@implementation LSLabelTextView {   MASConstraint *_toLeftBtnMasConstraint;   MASConstraint *_toTopBtnMasonstraint;   MASConstraint *_toLeftSelfMasConstraint;   MASConstraint *_toTopSelfMasonstraint; } - (instancetype)initWithViewModel:(id<YCViewModelProtocol>)viewModel {   self.viewModel = (LSLabelTextViewModel *)viewModel;   return [super initWithViewModel:viewModel]; } - (void)yc_bindViewModel {   @weakify(self);   [[RACObserve(self, viewModel.dataArray) distinctUntilChanged] subscribeNext:^(id x) {     @strongify(self);     [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];     if (self.viewModel.dataArray.count <= 0) {       __weak UIView *weakNullView;       UIView *nullView = [[UIView alloc] init];       weakNullView = nullView;       [self addSubview:weakNullView];       WS(weakSelf)       [weakNullView mas_makeConstraints:^(MASConstraintMaker *make) {         make.top.right.left.bottom.equalTo(weakSelf);         make.height.equalTo(weakSelf.viewModel.nullHeight);       }];       return;     }     NSInteger lineNum = 1;     CGFloat allWidth = 0;     __weak UIButton *lastBtn;     for (int i = 0; i < self.viewModel.dataArray.count; i++) {        NSString *string = [self.viewModel.dataArray stringWithIndex:i];       __weak UIButton *weakBtn = [self ls_getBtnWithString:string];       [self addSubview:weakBtn];       CGSize size = [string widthWithHeight:20 andFont:self.viewModel.textFontNum];       CGFloat needFloat = size.width < self.viewModel.miniWidth ? self.viewModel.miniWidth : size.width;       if (lastBtn) {         WS(weakSelf)         [weakBtn mas_makeConstraints:^(MASConstraintMaker *make) {           _toLeftBtnMasConstraint = make.left.equalTo(lastBtn.mas_right).offset(weakSelf.viewModel.labelHorizontalSpace);           [_toLeftBtnMasConstraint activate];           _toTopBtnMasonstraint = make.top.equalTo(lastBtn.mas_bottom).offset(weakSelf.viewModel.labelVerticalSpace);           [_toTopBtnMasonstraint deactivate];           _toLeftSelfMasConstraint = make.left.equalTo(weakSelf.viewModel.leftToViewEdge);           _toTopSelfMasonstraint = make.top.equalTo(lastBtn);           make.size.equalTo(CGSizeMake(needFloat + 20, weakSelf.viewModel.labelHeight));         }];         if (allWidth + self.viewModel.labelHorizontalSpace + needFloat + 20 + self.viewModel.rightToViewEdge > self.viewModel.allWidth) {           [_toLeftSelfMasConstraint activate];           [_toLeftBtnMasConstraint deactivate];           [_toTopBtnMasonstraint activate];           [_toTopSelfMasonstraint deactivate];           lineNum ++;           allWidth = self.viewModel.leftToViewEdge + needFloat + 20;         } else {           [_toLeftSelfMasConstraint deactivate];           [_toLeftBtnMasConstraint activate];           [_toTopBtnMasonstraint deactivate];           [_toTopSelfMasonstraint activate];           allWidth = allWidth + self.viewModel.labelHorizontalSpace + needFloat + 20;         }       } else {         WS(weakSelf)         [weakBtn mas_makeConstraints:^(MASConstraintMaker *make) {           make.left.equalTo(weakSelf.viewModel.leftToViewEdge);           make.size.equalTo(CGSizeMake(needFloat + 20, weakSelf.viewModel.labelHeight));           make.top.equalTo(weakSelf.viewModel.topToViewEdge);         }];         allWidth = allWidth + self.viewModel.leftToViewEdge + needFloat + 20;       }       lastBtn = weakBtn;     }     WS(weakSlef)     [lastBtn mas_updateConstraints:^(MASConstraintMaker *make) {       make.bottom.equalTo(weakSlef.viewModel.bottomToViewEdge);     }];   }]; } - (UIButton *)ls_getBtnWithString:(NSString *)string {   UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];   btn.layer.borderWidth = 0.5;   btn.layer.borderColor = self.viewModel.borderColor.CGColor;   [btn setTitleColor:self.viewModel.titleColor forState:UIControlStateNormal];   btn.backgroundColor = self.viewModel.backgroundColor;   btn.layer.masksToBounds = YES;   btn.layer.cornerRadius = self.viewModel.cornerRadius;   btn.titleLabel.font = YC_YAHEI_FONT(self.viewModel.textFontNum);   [btn setTitle:string forState:UIControlStateNormal];   btn.ls_typeString = string;   return btn; }@endViewModel适配LSLabelTextViewModel.h的实现//// LSLabelTextViewModel.h// RenCheRen//// Created by 王隆帅 on 15/12/30.// Copyright &copy; 2015年 王隆帅. All rights reserved.//#import "YCViewModel.h"@interface LSLabelTextViewModel : YCViewModel/**  * 标签数组  */@property (nonatomic, strong) NSMutableArray *dataArray;/**  * 总的宽度  */@property (nonatomic, assign) CGFloat allWidth;/**  * 没有标签时的高度  */@property (nonatomic, assign) CGFloat nullHeight;/**  * 文字字体大小  */@property (nonatomic, assign) CGFloat textFontNum;/**  * 取得标签为空的时候,标签最小长度  */@property (nonatomic, assign) CGFloat miniWidth;/**  * 标签高度  */@property (nonatomic, assign) CGFloat labelHeight;/**  * 最左侧标签距离View的边缘的宽度  */@property (nonatomic, assign) CGFloat leftToViewEdge;/**  * 最右侧标签距离View的边缘的宽度  */@property (nonatomic, assign) CGFloat rightToViewEdge;/**  * 最上侧标签距离View的边缘的宽度  */@property (nonatomic, assign) CGFloat topToViewEdge;/**  * 最下侧标签距离View的边缘的宽度  */@property (nonatomic, assign) CGFloat bottomToViewEdge;/**  * 横向标签之间的宽度  */@property (nonatomic, assign) CGFloat labelHorizontalSpace;/**  * 纵向标签之间的宽度  */@property (nonatomic, assign) CGFloat labelVerticalSpace;/**  * label(btn) 的相关属性  */@property (nonatomic, assign) CGFloat borderWidth;@property (nonatomic, strong) UIColor *borderColor;@property (nonatomic, strong) UIColor *titleColor;@property (nonatomic, strong) UIColor *backgroundColor;@property (nonatomic, assign) CGFloat cornerRadius;@endLSLabelTextViewModel.m的实现//// LSLabelTextViewModel.m// RenCheRen//// Created by 王隆帅 on 15/12/30.// Copyright &copy; 2015年 王隆帅. All rights reserved.//#import "LSLabelTextViewModel.h"@implementation LSLabelTextViewModel- (NSMutableArray *)dataArray {   if (!_dataArray) {     _dataArray = [[NSMutableArray alloc] init];   }   return _dataArray; }@end感谢你能够认真阅读完这篇文章,希望小编分享的“iOS中标签Tag列表怎么用”这篇文章对大家有帮助,同时也希望大家多多支持辰讯云,关注辰讯云资讯频道,更多相关知识等着你来学习!...

小编给大家分享一下Android开发如何实现Launcher3应用列表修改透明背景,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!具体如下:Launcher时开机完成后第一个启动的应用,用来展示应用列表和快捷方式、小部件等。Launcher作为第一个(开机后第一个启动的应用)展示给用户的应用程序,其设计的好坏影响到用户的体验,甚至影响用户购机的判断。所以很多品牌厂商都会不遗余力的对Launcher进行深度定制,如小米的MIUI、华为的EMUI等。Android默认的Launcher没有过多的定制,更加简洁,受到源生党的追捧,Google的Nexus系列手机基本都是用的源生Launcher,目前Android源生的Launcher版本是Launcher3。前面总结了一些常见的launcher3配置修改方法,这里来分析一下launcher3的应用列表背景的修改技巧。将launcher3的应用列表背景修改为透明,与Launcher2略有不同,需要进行如下步骤:1. 找到res/layout/apps_customize_pane.xml文件,将<com.android.launcher3.appscustomizetabhostxmlns:android="http://schemas.android.com/apk/res/android"xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"android:background="#FF000000">修改为:<com.android.launcher3.appscustomizetabhostxmlns:android="http://schemas.android.com/apk/res/android"xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"android:background="#00000000">将动画部分<frameLayoutandroid:id="@+id/animation_buffer" android:layout_width="match_parent"android:layout_height="match_parent"android:background="#FF000000"android:visibility="gone" />修改为:<frameLayout android:id="@+id/animation_buffer" android:layout_width="match_parent"android:layout_height="match_parent"android:background="#00000000"android:visibility="gone" />2、找到AppsCustomizeTabHost.java类中的onTabChangedEnd()方法,如下:private void onTabChangedEnd(AppsCustomizePagedView.ContentType type) {     int bgAlpha = (int) (255 * (getResources().getInteger(       R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f));     setBackgroundColor(Color.argb(bgAlpha, 0, 0, 0));     mAppsCustomizePane.setContentType(type); }其中bgAlpha为透明度的参数,将其改为你需要的透明度即可,255为不透明,以上1、2步骤完之后,保存,编译,即可达到需要的效果。看完了这篇文章,相信你对“Android开发如何实现Launcher3应用列表修改透明背景”有了一定的了解,如果想了解更多相关知识,欢迎关注辰讯云资讯频道,感谢各位的阅读!...

这篇文章给大家介绍springboot中怎么设置启动端口,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。可以通过实现EmbeddedServletContainerCustomizer接口来实现:public class Application extends SpringBootServletInitializer implements EmbeddedServletContainerCustomizer {   @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {    return builder.sources(Application.class);   }   public static void main(String[] args) {    SpringApplication.run(Application.class, args);   }   @Override public void customize(ConfigurableEmbeddedServletContainer container) {    container.setPort(8081);   }  }关于springboot中怎么设置启动端口就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。...