iOS动画和特效(四)controller间的自定义过渡效果
来源:互联网 发布:dsp算法工程师 编辑:程序博客网 时间:2024/06/06 15:46
iOS动画和特效(四)controller间的自定义过渡效果
前面动画和特效系类文章中有一篇写了UIView的过渡效果,而这一篇主要说的是UIViewController的自定义过渡效果和过渡交互
先看看完成后的效果图
- 点击模态controller,会弹出一个新的绿色UIViewController,手指下滑可以dismiss这个controller
- 四个角的按钮可以自定义圆形切换的过渡效果切换的一个红色的UIViewController,点击返回用同样的方式切换回来
出场人物介绍
介绍下Controller过渡和交互用到的类
presention and presented
A中模态显示B,那么A就是presention,b就是presented,后续内容会使用这种叫法称呼Modal下的2个controller
UIViewControllerTransitioningDelegate
controller modal过渡的presented和dismiss的动画交互协议,你需要实现协议,它会询问你:
- 当PresentedController时,你要使用怎样的动画类(UIViewControllerAnimatedTransitioning)展示过渡效果?
- 当DismissedController时,你要使用怎样的动画类(UIViewControllerAnimatedTransitioning)展示过渡效果?
- 当PresentedController时,你要使用怎样的过渡交互类(UIViewControllerInteractiveTransitioning)处理过渡交互?
- 当DismissedController时,你要使用怎样的过渡交互类(UIViewControllerInteractiveTransitioning)处理过渡交互?
- presentationControllerForPresentedViewController:这篇文章没有用到,应该是自定义modal状态呈现和被呈现的controller,类似于controller的PresentationStyle,想了解的可以参考下面两篇文章 Present ViewController Modally 和 iOS 8的PresentationController
UIViewControllerAnimatedTransitioning
过渡动画效果的具体实现的接口,需要实现它的3个方法,即可完成一个controller过渡动画效果
func animationEnded
:过渡动画完成后要执行的代码可以写到这个方法中func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval
:给定一个过渡动画的执行时间func animateTransition(transitionContext: UIViewControllerContextTransitioning)
:具体过渡动画都在这个方法里面实现,在这个方法中可以通过transitionContext拿到一切你需要的对象,后面会有讲到
UINavigationControllerDelegate
controller 非模态状态下的的过渡动画,就不能使用之前说的那个UIViewControllerTransitioningDelegate
委托解决了,就需要用UINavigationControllerDelegate
,接口方法比较类似,但也不完全一样
- 你要使用怎样的动画类(UIViewControllerAnimatedTransitioning)展示过渡效果?
- 你要使用怎样的过渡交互类(UIViewControllerInteractiveTransitioning)处理过渡交互?
- willShowViewController,didShowViewController : 生命周期事件
- navigationControllerSupportedInterfaceOrientations: 屏幕支持的方向
UIViewControllerInteractiveTransitioning
这个类用于实现在转场过路效果中的交互,比如在demo中,用它实现了一个手指下滑解除modal状态的效果
UIViewControllerContextTransitioning
UIViewControllerAnimatedTransitioning协议的关键方法animateTransition(transitionContext: UIViewControllerContextTransitioning)
里面可以得到,使用transitionContext可以获取一些重要的上下文信息,比如前后的controller,转换时的容器等,示例如下
//拿到前后的两个controller let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)! let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)! //拿到Presenting的最终Frame let finalFrameForVC = transitionContext.finalFrameForViewController(toVC) //拿到转换的容器view let containerView = transitionContext.containerView() //拿到过渡动画执行时间 transitionDuration(transitionContext)
controller modal过渡效果
我们先来实现一个简单的示例,点击一个按钮,出现一个modal controller,自定义从下往上弹出并且有些回弹效果的过渡动画。从这个例子中我们可以了解
- 如何实现UIViewControllerTransitioningDelegate
- 如何实现UIViewControllerAnimatedTransitioning
- 如何组合在一起完成功能
示例效果见demo点击后,弹出的绿色界
步骤1:界面画出按钮,点击之后用 modal 显示 To2ViewController,并设置transitioningDelegate指向自己
//模态视图切换效果 @IBAction func Transitioning2(sender: AnyObject) { let toVC = To2ViewController() //设置transitioning委托为自己 toVC.transitioningDelegate = self navigationController?.presentViewController(toVC, animated: true, completion: nil) }
步骤2:controller 实现 UIViewControllerTransitioningDelegate
demo中使用了extension的方式继承UIViewControllerTransitioningDelegate,好处是代码逻辑分离
//模态视图切换效果extension ControllerTransitioningDemoViewController:UIViewControllerTransitioningDelegate{ //返回Presented使用的UIViewControllerAnimatedTransitioning类 func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning?{ return PresentedAnimation() // PresentedAnimation 是自定义的过渡动画效果的实现类,继承自UIViewControllerAnimatedTransitioning 步骤3中介绍它 }}
步骤3: 实现一个过渡效果为自下而上弹出并有些晃动的UIViewControllerAnimatedTransitioning类
就如之前对UIViewControllerAnimatedTransitioning介绍的那样,需要继承自UIViewControllerAnimatedTransitioning,然后实现它的三个委托方法,具体实现请看代码注释
import UIKitpublic class PresentedAnimation: NSObject,UIViewControllerAnimatedTransitioning { public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval{ //转场过渡动画的执行时间 return 0.6 } // This method can only be a nop if the transition is interactive and not a percentDriven interactive transition. //在进行切换的时候将调用该方法,我们对于切换时的UIView的设置和动画都在这个方法中完成。 public func animateTransition(transitionContext: UIViewControllerContextTransitioning){ //拿到前后的两个controller let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)! let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)! //拿到Presenting的最终Frame let finalFrameForVC = transitionContext.finalFrameForViewController(toVC) //拿到转换的容器view let containerView = transitionContext.containerView() let bounds = UIScreen.mainScreen().bounds toVC.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height) containerView!.addSubview(toVC.view) //自下而上弹出toVC的动画 UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.0, options: .CurveLinear, animations: { fromVC.view.alpha = 0.5 toVC.view.frame = finalFrameForVC }, completion: { finished in transitionContext.completeTransition(true) fromVC.view.alpha = 1.0 }) NSLog("animateTransition") } //执行完成后的回调 public func animationEnded(transitionCompleted: Bool){ NSLog("animation ended") }}
madal的转场动画分为2类,present和dismiss,刚才我们实现的是animationControllerForPresentedController,这是present类,下节我们实现dissmiss的转场过渡效果
controller dismiss过渡效果
present的过渡效果实现和modal过渡效果类似,也是设置委托、实现委托、实现动画,就不详细说明了,大家可以参考demo。这里我们只说说和present过渡的区别
区别1 委托入口不同
//Presented使用的委托 func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning?{ } //Dismiss使用的委托 func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { //返回一个UIViewControllerAnimatedTransitioning类型 return DismissAnimation() }
区别2 动画效果区别(这点其实不算真正的区别,因为你也可以设置为相同的效果):demo中present动画是从下而上,而dismiss的动画是自上而下。
DismissAnimation的实现
import UIKitclass DismissAnimation:NSObject,UIViewControllerAnimatedTransitioning { func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval{ return 0.6 } func animateTransition(transitionContext: UIViewControllerContextTransitioning){ let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)! let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)! let screenBounds = UIScreen.mainScreen().bounds let initFrame = transitionContext.initialFrameForViewController(fromVC) let finalFrame = CGRectOffset(initFrame, 0, screenBounds.size.height) let containerView = transitionContext.containerView()! containerView.addSubview(toVC.view) containerView.sendSubviewToBack(toVC.view) let duration: NSTimeInterval = self.transitionDuration(transitionContext) UIView.animateWithDuration(duration, animations: { fromVC.view.frame = finalFrame }, completion: { (finished: Bool) in transitionContext.completeTransition(!transitionContext.transitionWasCancelled()) }) }}
controller push、pop过渡效果
push、pop和present、dismiss的过渡走的是两个完全不同的委托,委托里面的方法有相似之处,比如都可以分为过渡和交互两类。交互的内容后面再说,先说过渡效果的区别。
实现的委托不同: push、pop自定义过渡动画,需要实现UINavigationControllerDelegate,而present、dismiss实现的是UIViewControllerTransitioningDelegate
区分类型方式不同: UIViewControllerTransitioningDelegate通过2个委托present和dismiss区分开来,而在UINavigationControllerDelegate中,对应转场过渡动画只有一个委托,通过委托中的参数operation: UINavigationControllerOperation 区分pop和push
//push、pop视图切换extension ControllerTransitioningDemoViewController:UINavigationControllerDelegate{ func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?{ let transitioningAnimation = ExpandAnimation(type:operation) transitioningAnimation.sender = transitioningSender //返回动画的实现类 return transitioningAnimation }}
UIViewControllerAnimatedTransitioning动画类的实现,完成点击后圆形区域放大过渡的动画效果
步骤1添加一个按钮,点击使用push的方式跳转到页面To1ViewController,并设置委托
//推出视图切换效果 @IBAction func Transitioning1(sender: AnyObject) { let toVC = To1ViewController() //设置委托 navigationController?.delegate = self //主要是动画实现圆形扩大效果,需要知道一个初始园的位置,所以把uiview传过去。这种方式传递uiview不是一个很好的方式,这里为了demo能尽量的简单,所以这么做了 transitioningSender = sender as! UIView navigationController?.pushViewController(toVC, animated: true) }
步骤2实现UINavigationControllerDelegate
//push、pop视图切换extension ControllerTransitioningDemoViewController:UINavigationControllerDelegate{ func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?{ let transitioningAnimation = ExpandAnimation(type:operation) transitioningAnimation.sender = transitioningSender //返回动画的实现类 return transitioningAnimation }}
步骤3 完成点击后圆形区域放大过渡的动画效果的实现类ExpandAnimation
这个动画效果我就简单说说实现步骤,其余的大家看看代码。下面的参考文章中,有一篇对这个效果说的比较详细,大家可以去阅读
实现这样一个效果,基本原理是使用遮罩层,罩住presenting,有一个小圆是初始按钮点击的圆形路径,一个大圆是大于presenting的圆形路径。大圆和小圆作为遮罩的路径。判断过渡类型是presention -》 presenting还是presenting -》 presention,分别做不同的处理
presention -》 presenting : 小圆作为初始遮罩层路径,罩住presenting,使用baseAnimation动画把遮罩层的路径从小圆路径变为大圆路径,presenting即可显示出来,完成过渡效果。 小圆的位置是通过跳转点击按钮决定的,小圆位置不同会影响到大圆结束的位置,所以分了左上、左下、右上、右下四个位置分别处理。这个步骤由于偷懒在presenting -》 presention这个过程里面被省略了,每次都指定了固定的小圆位置
presenting -》 presention : 使用大圆遮住presenting,使用baseAnimation动画把遮罩层的路径从大圆路径变为小圆路径,presenting慢慢变小到看不见,presention慢慢即可显示出来,完成过渡效果。
import UIKitclass ExpandAnimation: NSObject, UIViewControllerAnimatedTransitioning { //保存上下文 var transitionContext:UIViewControllerContextTransitioning! //Pop or push var type:UINavigationControllerOperation! //初始点击的uiview对象,需要他的frame作为初始位置 var sender:UIView? convenience init(type:UINavigationControllerOperation) { self.init() self.type = type } func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval{ return 0.5 } func animateTransition(transitionContext: UIViewControllerContextTransitioning){ self.transitionContext = transitionContext NSLog("animateTransition") if(type == .Push){ PushTransition(transitionContext) }else if(type == .Pop){ PopTransition(transitionContext) } } func animationEnded(transitionCompleted: Bool){ NSLog("animation ended") } //弹出效果 在固定位置进行的动画,可以根据需要改成动态位置触发 func PopTransition(transitionContext: UIViewControllerContextTransitioning){ let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)! let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)! let containerView = transitionContext.containerView() let view = toVC.view! containerView!.addSubview(toVC.view) containerView!.addSubview(fromVC.view) //遮罩层 let mask = CAShapeLayer() fromVC.view.layer.mask = mask //画出小圆 let s_center = CGPoint(x: 50, y: 50) let s_radius:CGFloat = sqrt(800) let s_maskPath = UIBezierPath(ovalInRect:CGRectInset(CGRect(x: s_center.x, y: s_center.y, width: 1, height: 1), -s_radius, -s_radius)) // mask.path = s_maskPath.CGPath //画出大圆 let l_center = CGPoint(x: 50, y: 50) let l_radius = sqrt( pow(view.bounds.width - l_center.x, 2) + pow(view.bounds.height - l_center.y, 2) ) + 150 let l_maskPath = UIBezierPath(ovalInRect:CGRectInset(CGRect(x: l_center.x, y: l_center.y, width: 1, height: 1), -l_radius, -l_radius)) let baseAnimation = CABasicAnimation(keyPath: "path") baseAnimation.duration = transitionDuration(transitionContext) baseAnimation.fromValue = l_maskPath.CGPath baseAnimation.toValue = s_maskPath.CGPath baseAnimation.delegate = self baseAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) mask.addAnimation(baseAnimation, forKey: "path") } //present 动画,根据触发点的位置开始启动动画 func PushTransition(transitionContext: UIViewControllerContextTransitioning){ let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)! let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)! let finalFrame = transitionContext.finalFrameForViewController(toVC) let containerView = transitionContext.containerView() let view = toVC.view! containerView!.addSubview(toVC.view) //小圆路径 let s_maskPath = UIBezierPath(ovalInRect:(sender?.frame)!) //大圆路径 let l_center = (sender?.center)! var l_radius:CGFloat if(sender!.frame.origin.x > (toVC.view.bounds.size.width / 2)){ if (sender!.frame.origin.y < (toVC.view.bounds.size.height / 2)) { //右上角 l_radius = sqrt( pow(0 - l_center.x, 2) + pow(CGRectGetMaxY(view.frame) - l_center.y, 2) ) }else{ //右下角 l_radius = sqrt( pow(0 - l_center.x, 2) + pow(0 - l_center.y, 2) ) } }else{ if (sender!.frame.origin.y < (toVC.view.bounds.size.height / 2)) { //左上角 l_radius = sqrt( pow(CGRectGetMaxX(view.frame) - l_center.x, 2) + pow(CGRectGetMaxY(view.frame) - l_center.y, 2) ) }else{ //左下角 l_radius = sqrt( pow(CGRectGetMaxX(view.frame) - l_center.x, 2) + pow(0 - l_center.y, 2) ) } } l_radius += 50 //稍微增加一些位置 let l_maskPath = UIBezierPath(ovalInRect:CGRectInset(CGRect(x: l_center.x, y: l_center.y, width: 1, height: 1), -l_radius, -l_radius)) //遮罩层 let mask = CAShapeLayer() mask.path = l_maskPath.CGPath view.layer.mask = mask ////错误用法,animationWithDuration不能通过操作layer产生动画 //UIView.animateWithDuration(5) { () -> Void in // mask.path = b_maskPath.CGPath //} let baseAnimation = CABasicAnimation(keyPath: "path") baseAnimation.duration = transitionDuration(transitionContext) baseAnimation.fromValue = s_maskPath.CGPath baseAnimation.toValue = l_maskPath.CGPath baseAnimation.delegate = self baseAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) mask.addAnimation(baseAnimation, forKey: "path") } override func animationDidStop(anim: CAAnimation, finished flag: Bool) { //动画完成后去处遮罩 self.transitionContext.completeTransition(true) //动画完成后去处遮罩 self.transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)?.view.layer.mask = nil self.transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)?.view.layer.mask = nil }}
自定义过渡交互,实现一个下滑手势解除modal状态的效果
UINavigationControllerDelegate和UIViewControllerTransitioningDelegate委托都有对交互的方法支持,返回一个UIViewControllerInteractiveTransitioning对象,他是实现过渡交互的具体实现。
这里我们只实现UIViewControllerTransitioningDelegate的交互,UINavgationController的实现和它类似。这个demo参考了猫神的文章:iOS7中的ViewController切换 区别是,这里使用swift实现。猫神在他的文章中有几个地方没看明白,后来自己写了一遍才明白,这里会仔细说明下。
第一步:实现interactionControllerForDismissal委托
//present、dismiss视图切换效果 extension ControllerTransitioningDemoViewController:UIViewControllerTransitioningDelegate{ ... //返回dismiss使用的UIViewControllerAnimatedTransitioning类 func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return DismissAnimation() } //返回dismiss交互时的使用的UIViewControllerInteractiveTransitioning类 func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { return interactiveTransition.isInteracting ? interactiveTransition : nil } }
第二步:完成DismissAnimation动画效果
DismissAnimation动画和前文中的PresentedAnimation动画效果类似,只是一个自下而上一个自上而下
import UIKitclass DismissAnimation:NSObject,UIViewControllerAnimatedTransitioning { func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval{ return 0.6 } func animateTransition(transitionContext: UIViewControllerContextTransitioning){ let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)! let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)! let screenBounds = UIScreen.mainScreen().bounds let initFrame = transitionContext.initialFrameForViewController(fromVC) let finalFrame = CGRectOffset(initFrame, 0, screenBounds.size.height) let containerView = transitionContext.containerView()! containerView.addSubview(toVC.view) containerView.sendSubviewToBack(toVC.view) let duration: NSTimeInterval = self.transitionDuration(transitionContext) UIView.animateWithDuration(duration, animations: { fromVC.view.frame = finalFrame }, completion: { (finished: Bool) in transitionContext.completeTransition(!transitionContext.transitionWasCancelled()) }) }}
第三步:完成SwipeUpInteractiveTransition交互处理
SwipeUpInteractiveTransition继承自UIPercentDrivenInteractiveTransition,UIPercentDrivenInteractiveTransition继承UIViewControllerInteractiveTransitioning,使用UIPercentDrivenInteractiveTransition可以帮你省许多事情。
实现的原理是让SwipeUpInteractiveTransition监控presenting view的手势,检测手指y位置的移动,如果超过200,则标志为完成。大家可以看下代码,交互实现主要是那三个方法的运用。
- updateInteractiveTransition() : 更新界面,实际效果就是手指上下移动时presenting会跟着上下移动
- cancelInteractiveTransition(): 取消交互,页面恢复presenting
- finishInteractiveTransition(): 完成交互,页面切到presention
import UIKit class SwipeUpInteractiveTransition: UIPercentDrivenInteractiveTransition { var vc:UIViewController? //是否正在交互 var isInteracting:Bool = false //是否判断交互完成 var shouldComplete:Bool = false init(vc:UIViewController) { super.init() self.vc = vc //添加手势 vc.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "panGestureHandler:")) } //处理滑动手势 func panGestureHandler(gesture:UIPanGestureRecognizer){ let translation = gesture.translationInView(gesture.view) switch(gesture.state){ case .Began: //标记交互开始,dismiss model isInteracting = true vc?.dismissViewControllerAnimated(true, completion: nil) case .Changed: var fraction = Float(translation.y / 400) //限制fraction值在0-1之间 fraction = fminf(fmaxf(fraction, 0.0), 1.0) shouldComplete = fraction > 0.5 updateInteractiveTransition(CGFloat(fraction)) NSLog("x:%f y:%f" , translation.x,translation.y) NSLog("fraction:%f" , fraction) NSLog("shouldComplete:%@" ,shouldComplete) case .Ended , .Cancelled: isInteracting = false if(!shouldComplete || gesture.state == .Cancelled){ cancelInteractiveTransition() }else{ finishInteractiveTransition() } default:break } } }
这里要注意下,为什么.Began时候就要执行 vc?.dismissViewControllerAnimated(true, completion: nil)
,因为执行dismiss的时候不会直接dismiss,会进入interactionControllerForDismissal委托问你要UIViewControllerInteractiveTransitioning, 因为设置了标志位isInteracting,所以会返回SwipeUpInteractiveTransition,接着处理手指移动和移动结束事件。涉及到很多委托方法的先后发生顺序的问题,请看下节内容
controller过渡和UIViewController的委托事件发生的先后顺序
presention -》 presenting :弹出模态视图过程
presenting viewWillAppear animateTransition start presenting viewDidAppear presention viewDidDisappear animateTransition ended
presenting -》presention :解除模态视图过程
presention viewWillAppear animateTransition start presention viewDidAppear presenting viewDidDisappear animateTransition ended
可以看出来,animate 发生在 viewWillAppear和viewDidAppear之间的,并且在viewDidDisappear后,animateTransition才结束。了解这些的发生先后顺序,对理解整个过渡动画的处理过程很好帮助
demo
- iOS动画和特效(四)controller间的自定义过渡效果
- iOS动画和特效(四)controller间的自定义过渡效果
- 自定义iOS的过渡动画的效果
- 动画和过渡效果
- css3的转换效果过渡效果动画效果和列
- iOS学习之——自定义过渡动画的实现和使用
- ios开发 自定义带弧度的UITabBar,保留系统原有push和pop过渡效果
- CSS-过渡效果和动画效果
- CSS伪类的动画和过渡效果应用
- ios uivew过渡动画 翻页效果
- META标签特效(页面过渡效果)
- 自定义NavigationController 的Push 和 Pop过渡动画
- iOS 过渡动画的实现
- iOS动画和特效(三)MotionEffects
- iOS动画和特效(三)MotionEffects
- iOS动画技术——iOS 7自定义过渡动画
- 自定义Push和Pop过渡动画
- UIView动画(过渡效果)的学习笔记
- ELK学习
- YJUtilsScreenSize
- java request和response的区别
- YJUtilsDeviceType
- YJUtilsAPP
- iOS动画和特效(四)controller间的自定义过渡效果
- 从Spark架构中透视job
- YJUtilsUserInterfaceIdiom
- MongoDB模型
- uvaoj10474---详解细节(二分法)注意!
- poj2253——Frogger(最小生成树,prim算法)
- linux服务器安全配置实例(三)用户账户权限配置
- tomcat数据库连接池配置
- Vim 启动错误Caught deadly signal SEGV