
我知道自己可以用xcode建立一个工程。然后运行就好了 UIButton butt = [UIButton buttonWithType:UIButtonTypeCustom]; buttframe = CGRectMake(100, 100, 50, 50); [butt setTitle:@"哈哈哈" forState:UIControlStateNormal]; [butt setTitle
第一种:通过人为的办法改变viewtransform的属性。
具体办法:
viewtransform一般是View的旋转,拉伸移动等属性,类似viewlayertransform,区别在于 Viewtransform是二维的,也就是使用仿射的办法通常就是带有前缀CGAffineTransform的类(可以到API文档里面搜索这个前 缀的所有类),而viewlayertransform可以在3D模式下面的变化,通常使用的都是前缀为CATransform3D的类。
这里要记住一点,当你改变过一个viewtransform属性或者viewlayertransform的时候需要恢复默认状态的话,记得先把他 们重置可以使用viewtransform = CGAffineTransformIdentity,或者viewlayertransform = CATransform3DIdentity,假设你一直不断的改变一个viewtransform的属性,而每次改变之前没有重置的话,你会发现后来 的改变和你想要的发生变化了,不是你真正想要的结果。
好了,上面介绍了旋转的属性,接下来就是关键了。官方提供了一个办法就是查看当前电池条的状态UIInterfaceOrientation orientation = [UIApplication sharedApplication]statusBarOrientation;通过这个办法,你可以知道当前屏幕的电池条的显示方向,而且你还可以 强制设置他的显示方向,通过设置这个属性就OK了,可以选择是否动画改变电池条方向。有了这两个那我们就可以任意的改变我们想要的显示方式了。
1获取当前电池条的方向UIInterfaceOrientation orientation = [UIApplication sharedApplication]statusBarOrientation
2获取当前屏幕的大小CGRect frame = [UIScreen mainScreen]applicationFrame;
3设置我们的View的中心点
CGPoint center = CGPointMake(frameoriginx + ceil(framesizewidth/2), frameoriginy + ceil(framesizeheight/2));
4根据当前电池条的方向,获取需要旋转的角度的大小。通常
if (orientation == UIInterfaceOrientationLandscapeLeft) {
return CGAffineTransformMakeRotation(M_PI15);
} else if (orientation == UIInterfaceOrientationLandscapeRight) {
return CGAffineTransformMakeRotation(M_PI/2);
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
return CGAffineTransformMakeRotation(-M_PI);
} else {
return CGAffineTransformIdentity;
}
5可以动画的改变我们view的显示方式了
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeRight animated:YES];
CGFloat duration = [UIApplication sharedApplication]statusBarOrientationAnimationDuration;(获取当前电池条动画改变的时间)
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
//在这里设置viewtransform需要匹配的旋转角度的大小就可以了。
[UIView commitAnimations];
第二种:通过setOrientation:的办法强制性的旋转到一个特定的方向。
注意:Apple在30以后都不支持这个办法了,这个办法已经成为了私有的了,但是要跳过App Stroe的审核,需要一点巧妙的办法。
不要直接调用[[UIDevice currentDevice] setOrientation: UIInterfaceOrientationLandscapeRight]这样的办法来强制性的横屏,这样导致你的程序是很难通过App Store审核的。但是你可以选择使用performSelector的办法来调用它。具体就几行代码如下:
//强制横屏
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
[[UIDevice currentDevice] performSelector:@selector(setOrientation:)
withObject:(id)UIInterfaceOrientationLandscapeRight];
}
总结:如果第一种办法可以满足你需要的话,最好使用第一种办法,因为那个上 App Store肯定没问问题,但是第二种的话是需要冒风险的,但是如果你的结构太复杂了,导致使用第一种办法人为很难控制的话,可以尝试简单的使用第二种办 法。我在有米提供的sample里面就看到他使用了第二种简单的办法来显示横屏竖式的广告条。
因为初学iOS开发,对于layoutSubviews、drawRect等方法何时调用并不是了解得很透彻
所以在此记录一下,每当有新的发现都会在此更新,相信假以时日
这篇记录文能够产生丰富的内容以供我日后开发时的参考
本文章不设大小标题,仅以序号作为排版
iOS layout机制相关方法
- (CGSize)sizeThatFits:(CGSize)size
- (void)sizeToFit
——————-
- (void)layoutSubviews
- (void)layoutIfNeeded
- (void)setNeedsLayout
——————–
- (void)setNeedsDisplay
- (void)drawRect
--------------------
layoutSubviews在以下情况下会被调用:
1、init初始化不会触发layoutSubviews
但是是用initWithFrame 进行初始化时,当rect的值不为CGRectZero时,也会触发
2、当使用[self setNeedsDisplay]时会调用drawRect
3、当使用[self addSubview]会触发layoutSubviews
4、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
5、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
6、滚动一个UIScrollView会触发layoutSubviews
7、旋转Screen会触发父UIView上的layoutSubviews事件
刷新子对象布局
-layoutSubviews方法:这个方法,默认没有做任何事情,需要子类进行重写
-setNeedsLayout方法: 标记为需要重新布局,异步调用layoutIfNeeded刷新布局,不立即刷新,但layoutSubviews一定会被调用
-layoutIfNeeded方法:如果,有需要刷新的标记,立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews)
如果要立即刷新,要先调用[view setNeedsLayout],把标记设为需要布局,然后马上调用[view layoutIfNeeded],实现布局
在视图第一次显示之前,标记总是“需要刷新”的,可以直接调用[view layoutIfNeeded]
---------------------------------------
重绘
-drawRect:(CGRect)rect方法:重写此方法,执行重绘任务
-setNeedsDisplay方法:标记为需要重绘,异步调用drawRect
-setNeedsDisplayInRect:(CGRect)invalidRect方法:标记为需要局部重绘
sizeToFit会自动调用sizeThatFits方法;
sizeToFit不应该在子类中被重写,应该重写sizeThatFits
sizeThatFits传入的参数是receiver当前的size,返回一个适合的size
sizeToFit可以被手动直接调用
sizeToFit和sizeThatFits方法都没有递归,对subviews也不负责,只负责自己
----------------------------------------
layoutSubviews对subviews重新布局
layoutSubviews方法调用先于drawRect
setNeedsLayout在receiver标上一个需要被重新布局的标记,在系统runloop的下一个周期自动调用layoutSubviews
layoutIfNeeded方法如其名,UIKit会判断该receiver是否需要layout根据Apple官方文档,layoutIfNeeded方法应该是这样的
layoutIfNeeded遍历的不是superview链,应该是subviews链
drawRect是对receiver的重绘,能获得context
setNeedDisplay在receiver标上一个需要被重新绘图的标记,在下一个draw周期自动重绘,iphone device的刷新频率是60hz,也就是1/60秒后重绘
1发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的队列事件中
2UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常会先发送事件给应用程序的主窗口(keyWindow)
3主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件
事件的具体传递过程,如图:
一般事件的传递是从父控件传递到子控件的
例如:
点击了绿色的View,传递过程如下:UIApplication->Window->白色View->绿色View
点击蓝色的View,传递过程如下:UIApplication->Window->白色View->橙色View->蓝色View
如果父控件接受不到触摸事件,那么子控件就不可能接收到触摸事件
应用如何找到最合适的控件来处理事件?有以下准则
详述:
1主窗口接收到应用程序传递过来的事件后,首先判断自己能否接手触摸事件。如果能,那么在判断触摸点在不在窗口自己身上
2如果触摸点也在窗口身上,那么窗口会从后往前遍历自己的子控件(遍历自己的子控件只是为了寻找出来最合适的view)
3遍历到每一个子控件后,又会重复上面的两个步骤(传递事件给子控件,1判断子控件能否接受事件,2点在不在子控件上)
4如此循环遍历子控件,直到找到最合适的view,如果没有更合适的子控件,那么自己就成为最合适的view。
UIView不能接收触摸事件的三种情况:
寻找最合适的view过程,如图:
这里点击了橙色的那块区域,事件传递判断过程如下:
1UIApplication从事件队列中取出事件分发给UIWindow
2UIWindow判断自己是否能接受触摸事件,可以
3UIWindow判断触摸点是否在自己身上,是的。
4UIWindow从后往前便利自己的子控件,取出白1(aUIWindow的子控件只有一个,那就是白1)
5白1都满足最上面两个条件,遍历子控件橙2
特别说明:
( a白1的子控件有两个,绿2和橙2 )
( b添加顺序是,先添加绿2,后添加橙2 )
( c根据后添加的子控件先遍历的原则,肯定是先遍历橙2子控件 )
6橙2都满足最上面两个条件,遍历子控件,先取出红3
( a橙2的子控件有两个,蓝3和红3,注意黄4不属于橙2的子控件而是蓝3的子控件 )
( b添加顺序是,先添加蓝3,后添加红3 )
( c根据后添加的子控件先遍历的原则,肯定是先遍历红3子控件 )
7红3不满足条件2,取出蓝3
8蓝3也不满足条件2,最后最合适的控件是橙2
寻找合适的View用到两个重要方法:
什么时候调用?
只要事件一传递给一个控件,这个控件就会调用他自己的hitTest:withEvent:方法寻找合适的View
作用
寻找并返回最合适的view(能够响应事件的那个最合适的view)
注 意:不管这个控件能不能处理事件,也不管触摸点在不在这个控件上,
事件都会先传递给这个控件,随后再调用hitTest:withEvent:方法
hitTest:withEvent:底层调用流程:
事件传递给窗口或控件后,就调用hitTest:withEvent:方法寻找更合适的view。所以是,先传递事件,再根据事件在自己身上找更合适的view。
不管子控件是不是最合适的view,系统默认都要先把事件传递给子控件,经过子控件调用自己的hitTest:withEvent:方法验证后才知道有没有更合适的view。即便父控件是最合适的view了,子控件的hitTest:withEvent:方法还是会调用,不然怎么知道有没有更合适的!即,如果确定最终父控件是最合适的view,那么该父控件的子控件的hitTest:withEvent:方法也是会被调用的。
以上是事件传递的顺序:
上文介绍了事件的传递过程,找到合适的View之后就会调用该view的touches方法要进行响应处理具体的事件,找不到最合适的view,就不会调用touches方法进行事件处理。
这里先介绍一下响应者链条:响应者链条其实就是很多响应者对象(继承自UIResponder的对象)一起组合起来的链条称之为响应者链条
一般默认做法是控件将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理 (即调用super的touches方法)。
那么如何判断当前响应者的上一个响应者是谁呢?有以下两个规则:
1判断当前是否是控制器的View,如果是控制器的View,上一个响应者就是控制器
2如果不是控制器的View,上一个响应者就是父控件
响应过程如下图:
touch响应:
如果控制器也不响应响应touches方法,就交给UIWindow。如果UIWindow也不响应,交给UIApplication,如果都不响应事件就作废了。
最后总结来说一次完整的触摸事件的传递响应过程为:
UIApplication-->UIWindow-->递归找到最合适处理的控件-->控件调用touches方法-->判断是否实现touches方法-->没有实现默认会将事件传递给上一个响应者-->找到上一个响应者-->找不到方法作废
一句话总结整个过程是:触摸或者点击一个控件,然后这个事件会从上向下(从父->子)找最合适的view处理,找到这个view之后看他能不能处理,能就处理,不能就按照事件响应链向上(从子->父)传递给父控件
额外添加:
有了响应网为基础,事件的传递就比较简单,只需要选择其中一条响应链,但是选择那一条响应链来传递呢?为了弄清真个过程,我们先来查看一下从触摸硬件事件转化为UIEvent消息。
首先用户触摸屏幕,系统的硬件进程会获取到这个点击事件,将事件简单处理封装后存到系统中,由于硬件检测进程和当前运行的APP是两个进程,所以进程两者之间传递事件用的是端口通信。硬件检测进程会将事件放入到APP检测的那个端口。
其次,APP启动主线程RunLoop会注册一个端口事件,来检测触摸事件的发生。当时事件到达,系统会唤起当前APP主线程的Runloop。唤起原因就是端口触摸事件,主线程会分析这个事件。
最后,系统判断该次触摸是否导致了一个新的事件, 也就是说是否是第一个手指开始触碰,如果是,系统会先从响应网中 寻找响应链。如果不是,说明该事件是当前正在进行中的事件产生的一个Touch message, 也就是说已经有保存好的响应链。
ios 怎么获取一个view的位置
打开appstore进入应用,右上角的分享按钮(从右往左数第二个),拷贝连接即可。如下图:
如何获取一个view在布局中的位置public View getViewByPosition(int pos, ListView listView) {
final int firstListItemPosition = listViewgetFirstVisiblePosition();
final int lastListItemPosition = firstListItemPosition + listViewgetChildCount() - 1;
if (pos < firstListItemPosition || pos > lastListItemPosition ) {
return listViewgetAdapter()getView(pos, null, listView);
} else {
final int childIndex = pos - firstListItemPosition;
return listViewgetChildAt(childIndex);
}
} 已解决,通过这个方法就可以实现了获取item中的view
如何获取一个uicollectionviewcell的位置UICollectionViewCell cell = (UICollectionViewCell )[collectionView
cellForItemAtIndexPath:indexPath];一句话就能获取到点击cell的frame,十分好用,同样适用于tableView。
ios中怎么获取collectionview中cell的位置你在点击cell的时候调用 - (void)performSegueWithIdentifier:(NSString )identifier sender:(id)sender ;
那不是有个sender嘛,你可以给它传值。
然后在-(void)prepareForSegue:(UIStoryboardSegue )segue sender:(id)sender 里的sender,就是你刚传的那个值。
Flash中怎么通过代码来获取一个左上、右下的位置,_x和_y只能获取图像原点的位置。设左上坐标(x1,y1),右下坐标(x2,y2),原点坐标(x0,y0),元件名称为mcPic,则:
x1 = mcPicx - mcPicwidth/2
y1 = mcPicy - mcPicheight/2
x2 = mcPicx + mcPicwidth/2
y2 = mcPicy + mcPicheight/2
x0 = mcPicx
y0 = mcPicy
怎样通过qq获取一个人的位置信息
除了使用者本人定位,其他人无法获取,这属于隐私保护
android 怎么获取ActionBar上某个menu的位置Android 30以上的手机默认是不显示溢出菜单的,那如何强制在Android 44以下的手机显示溢出菜单呢?可以使用以下方法:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
强制actionbar显示overflow菜单
适配类似魅族手机无法显示溢出菜单的解决方案
上面已经解决了如何在Android 44以下的手机强制显示溢出菜单,下面来解决一些奇葩手机无法显示溢出菜单的问题。为什么魅族手机无法显示,了解到的是魅族没有所谓的actionbar,它们称为 artbar,看来是魅族的工程师把官方的actionbar进行了修改。一个字,坑!不过小巫想到了一个解决办法,我们每部手机都有自己的手机品牌,我们可以针对这些奇葩手机进行适配,溢出菜单我们就使用popupwindow来替代。
MATLAB中,怎么获取一个向量中最大的N个元素,并获取它们所在的位置v=rand(1,5)
[mv mi]=max(v)
%mv为最大值,mi为最大值索引,v(mi)=mv
[sv si]=sort(v,2,'descend')
%si为从大到小的序列,比如要去最大的3个数就是v(si(1:3))
ios地图定位怎么获取两个点之间的位置通常我们在手机端打开百度地图后,客户端会自动对我们所处的位置进行定位的。如果没有进行定位的话,你可以点击地图页面的左下角的圆形图标,见下图红色框中所示,点击之后会自动更新,并且显示定位的地址信息。
VBS中如何获取一个数组中最大值的位置以下VBS脚本可以实现这个功能:
Public Function getArrMaxValueIndex(ByVal arr)
Dim ix, ixMax
ixMax = 0
For ix = 1 To UBound(arr)
If ( arr(ixMax) < arr(ix) ) Then
ixMax = ix
End If
Next
getArrMaxValueIndex = ixMax
End Function
'Define array and index for max entry
Dim arr, ixMax
'Initialize the array
arr = Array(4, 1, 8, 6, 3,6)
'Get the index of the max value
ixMax = getArrMaxValueIndex(arr)
'Print result
MsgBox "Max value: " & arr(ixMax) & " was found at " & ixMax & " index"
查了一下, 觉得既然是statusBar在接受事件, 那么, 我们想在程序里实现, 肯定也要从statusBar这个对象入手, 可是API里没有地方下手 于是, 我就觉得, 这个功能是不是iOS系统提供的 但是对开发者隐藏了呢
在什么地方d出的alertView? 你有此一问,应该不是在appDelegate中吧。如果是那样的话,只能是递归遍历来找了
UIAlertView myAlert;
-(void)findAlertView:(UIView view) {
NSArray subViews = [view subViews];
for (UIView sView in subViews) {
if ([sView isKindOfClass:[UIAlertView class]]) {
myAlert =(UIAlertView )sView;
break;
}else {
[self findAlertView:sView];
}
}
}
在AppDelegate 中调用
[self findAlertView:selfwindow];
BOOL值 isShow直接标记,添加到superView时,isShow = YES,从superView移除时,isShow = NO。
某些情况下,需判断当前ViewController是否正在显示,比如后台网络请求报错,我们可能只希望在发起请求的页面d窗提示用户,当用户已经跳转到其他界面,不做d窗,减少对用户的干扰。
假如一个UIView对象当前正在显示,那么它的window属性肯定为非空值。虽然官方文档未说明UIView未显示时window属性的取值, 但是经过简单的测试,大部分情况下UIView未显示时,window的值为空,因此依据此判断当前UIViewController是否正在显示。
其原理是将两个view的坐标convert 到相对于同一个view的坐标,再对比
以上就是关于自动化测试 ios 怎么找到代码写的控件全部的内容,包括:自动化测试 ios 怎么找到代码写的控件、ios开发xcode6 ipad横竖屏怎么判断,怎么自适应控件、关于iOS自定义控件调用回显方法的一些记录(持续更新)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)