iOS: Resizing and positioning a new view added to app started in landscape - ios

I think this has probably been asked, but after reading a lot, I'm not sure I have found an answer.
When the app is rotated to landscape, I'm adding a new view to the main view. The new view is constructed and added in code like this:
UIView * newView = ....
[rootView addSubview:newView];
But because the simulator is rotated to landscape when I add the new view I get this:
+------------------------------------------------------+
+ +---------------------------------------------+ +
+ | | | +
+ | | | +
+ | newView | rootView | +
+ | (Landscape | (Landscape) | +
+ | but portrait size) | | () +
+ | | | +
+ | | | +
+ | | | +
+ | | | +
+ +---------------------------------------------+ +
+------------------------------------------------------+
So I added newView.bounds = rootView.bounds; newView.center = rootView.center; thinking that would position the newView directly over the top of the rootView, but instead I got this:
+------------------------------------------------------+
+ +---------------------------------------------+ +
+ | | +
+ | | +
+ |--------------------------+ rootView | +
+ | | (Landscape) | +
+ | newView | | () +
+ | (Landscape size, | | +
+ | but offset) | | +
+ | | | +
+ | | | +
+ +---------------------------------------------+ +
+------------------------------------------------------+
I'm trying to figure out why they are different even though I've set the bounds and centers to be the same.
Dumping out the views I get this:
rootView; frame = (0 0; 768 1024); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x98870a0>>
newView ; frame = (-128 128; 1024 768); autoresize = W+H; layer = <CALayer: 0x6e470a0>>
So it appears that the rootView is still 768w x 1024h, just rotated by a transform, and after setting bounds and centre, the new view is 1024w x 768h and offset by 128 points.

After some more playing around, I came up with this:
// Position the new view offscreen.
CGFloat width = rootView.bounds.size.width;
CGFloat height = rootView.bounds.size.height;
newView.frame = CGRectMake(0, height, width, height);
[rootView addSubview:newView];
// Animate to the center of the view.
[UIView animateWithDuration:1.0 animations:^{
newView.frame = CGRectMake(0,0, width, height);
}];
It works, I'm just wondering if there is a better solution.

Related

How can I run GEB from a Grails service?

I'm trying to run GEB from a web-service on Grails since I need to extract data from a page and use it on my aplication.
The server is suposed to scrap the info and then return it into a view.
If I run it from the grails console it works fine but when I run it from the service it doesn't work
here's the code
package com.bamboozled
import geb.Browser
import grails.transaction.Transactional
#Transactional
class ScraperService {
Data scrapIt(String nombreCiclo, String numeroSolicitud) {
//Variable con los datos a retornar
def d = new Data()
//Inicia el bot
Browser.drive {
go "http://some.page/page.php"
$("form").ciclo = nombreCiclo
$("form").nosol = numeroSolicitud
$("form").find("input", name: "BOTONACEPTAR").click()
def a = getAvailableWindows()
def data = [" "," "," "," "," "]
withWindow(a[1]) {
data[0] = $("td")[5].text()
data[1] = $("td")[6].text()
data[2] = $("td")[7].text()
data[3] = $("td")[8].text()
data[4] = $("td")[9].text()
}
d.numeroSolicitud = data[0]
d.avance = data[1]
d.seEncuentraEn = data[2]
d.numeroCheque = data[3]
d.cheque = data[4]
}
return d
}
}
Here is the controller where I call it
package com.bamboozled
class DataController {
static scaffold = true
def ScraperService
def index() { }
def form() {
}
def consulta(){
def p = Ciclo.findAll()
[solicitudes : p]
}
def resultados() {
def d = ScraperService.scrapIt(params.nombreCiclo, params.numeroSolicitud)
[res : d]
}
}
When I run it it gives this error
URI
/bamboozled/data/resultados
Class
java.lang.NoClassDefFoundError
Message
geb/Browser
Around line 200 of PageFragmentCachingFilter.java
197: if (CollectionUtils.isEmpty(cacheOperations)) {
198: log.debug("No cacheable annotation found for {}:{} {}",
199: new Object[] { request.getMethod(), request.getRequestURI(), getContext() });
200: chain.doFilter(request, response);
201: return;
202: }
203:
Around line 63 of AbstractFilter.java
60: try {
61: // NO_FILTER set for RequestDispatcher forwards to avoid double gzipping
62: if (filterNotDisabled(request)) {
63: doFilter(request, response, chain);
64: }
65: else {
66: chain.doFilter(req, res);
Around line 17 of grails-app/services/com/bamboozled/ScraperService.groovy
14: def d = new Data()
15:
16: //Inicia el bot
17: Browser.drive {
18:
19: go "http://http://some.page/page.php"
20:
Around line 20 of grails-app/controllers/com/bamboozled/DataController.groovy
17: }
18:
19: def resultados() {
20: def d = ScraperService.scrapIt(params.nombreCiclo, params.numeroSolicitud)
21: [res : d]
22: }
23:
Trace
Line | Method
->> 200 | doFilter in PageFragmentCachingFilter.java
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 63 | doFilter in AbstractFilter.java
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 748 | run . . . in java.lang.Thread
Caused by ControllerExecutionException: Runtime error executing action
->> 200 | doFilter in PageFragmentCachingFilter.java
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 63 | doFilter in AbstractFilter.java
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 748 | run . . . in java.lang.Thread
Caused by InvocationTargetException: null
->> 200 | doFilter in PageFragmentCachingFilter.java
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 63 | doFilter in AbstractFilter.java
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 748 | run . . . in java.lang.Thread
Caused by NoClassDefFoundError: geb/Browser
->> 17 | $tt__scrapIt in ScraperService.groovy
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 20 | resultados in DataController.groovy
| 200 | doFilter in PageFragmentCachingFilter.java
| 63 | doFilter in AbstractFilter.java
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 748 | run . . . in java.lang.Thread
Any idea of how can I make it run?

Grails removeFrom() issue

Inside my Applicant domain class I have the following:
static hasMany = [recommendationFiles:ApplicantFile]
static mapping = {recommendationFiles joinTable: [name:"LETTER_FILES", key: "APPLICANT_ID", column: "LETTER_ID"]}
When I do the following:
def applicant = Applicant.findByENumber(session.user.eNumber)
def applicantFiles = applicant.recommendationFiles
println applicantFiles
applicantFiles.each {
applicant.removeFromRecommendationFiles(it)
}
applicant.save(flush:true)
I get this as an error which makes no sense to me:
| Error 2015-04-08 10:41:59,570 [http-bio-8080-exec-10] ERROR errors.GrailsExceptionResolver - ConcurrentModificationException occurred when processi
ng request: [POST] /scholarshipsystem/specialized/index - parameters:
_action_reUpload: Re-Upload
Stacktrace follows:
Message: null
Line | Method
->> 793 | nextEntry in java.util.HashMap$HashIterator
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 828 | next in java.util.HashMap$KeyIterator
| 106 | reUpload in scholarshipSystem.SpecializedController$$EP9HMKbd
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 895 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker
| 918 | run . . . in ''
^ 662 | run in java.lang.Thread
There's a few ways to make this work. One way is to convert the list to an array and iterate over it.
def list = applicantFiles.toArray()
list.each {
applicant.removeFromRecommendationFiles(it)
}
Another way, if you're just removing the entire collection would be to...
applicant.recommendationFiles*.delete()
applicant.recommendationFiles.clear()

UITableView crashes because "Attempt to create two animations for cell" (iOS 7)

In an UITableView I am trying to exchange the position of two sections and to add a new row into one of them by using a batch update.
BEFORE:
+-------------------------------------+
| |
| |
| SECTION A - HEADER - TITLE |
|-------------------------------------|
| SECTION A - ROW X |
|-------------------------------------|
| SECTION A - ROW Y > |
|-------------------------------------|
| |
| |
|-------------------------------------|
| SECTION B - ROW X |
|-------------------------------------|
| |
| |
+-------------------------------------+
AFTER:
+-------------------------------------+
| |
| |
|-------------------------------------|
| SECTION B - ROW X |
|-------------------------------------|
| |
| |
| SECTION A - HEADER - TITLE |
|-------------------------------------|
| SECTION A - ROW X |
|-------------------------------------|
| SECTION A - ROW Z - NEW ROW | <---------
|-------------------------------------|
| SECTION A - ROW Y > |
|-------------------------------------|
| |
| |
+-------------------------------------+
Here is my code:
[self.tableView beginUpdates];
[self.tableView moveSection:from toSection:to]; // from: 0, to: 1
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; // indexPath.section: 1, indexPath.row: 1
[self.tableView endUpdates];
But the UITableView instance crashes and outputs the following:
2014-06-29 19:45:07.486 YouTube[3312:60b] *** Assertion failure in -[_UITableViewUpdateSupport _setupAnimationsForNewlyInsertedCells], /SourceCache/UIKit_Sim/UIKit-2935.137/UITableViewSupport.m:1173
2014-06-29 19:45:07.488 YouTube[3312:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempt to create two animations for cell'
*** First throw call stack:
(
0 CoreFoundation 0x0000000102447495 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001021a699e objc_exception_throw + 43
2 CoreFoundation 0x000000010244731a +[NSException raise:format:arguments:] + 106
3 Foundation 0x0000000101d42f19 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 189
4 UIKit 0x000000010101166c -[_UITableViewUpdateSupport(Private) _setupAnimationsForNewlyInsertedCells] + 7491
5 UIKit 0x000000010101aa81 -[_UITableViewUpdateSupport _setupAnimations] + 193
6 UIKit 0x0000000100e10615 -[UITableView _updateWithItems:updateSupport:] + 1639
7 UIKit 0x0000000100e0c000 -[UITableView _endCellAnimationsWithContext:] + 11615
...
Is it not possible to move a section and add a new row at the same time in a batch update?
I know this is an old question, but just ran into this myself on iOS 11.3. We have code that diffs old and new models and generates UITableView updates, and it explodes with the "more than one animation for cell" exception when a section is both moved and has any changes to its cells (insert/delete/update).
The only solution is to delete/insert the section in this case, rather than move. You could either always do this (and probably animate sub-optimally), or do what we do and track when cells change and do the move only when safe.
You should change dataSources as well.
- (void)exchangeTableSection
{
[self.tableView beginUpdates];
NSMutableArray *temp = self.data1;
self.data1 = self.data2;
self.data2 = temp;
[self.data1 insertObject:#"ROW Z - NEW ROW " atIndex:1];
[self.tableView moveSection:0 toSection:1];
[self.tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:1 inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (0 == section) {
return self.data1.count;
} else if (1 == section) {
return self.data2.count;
}
return 0;
}

My custom class has all the same variables

Below is a simplified example of my problem. I am trying to store the same object with different values. But when I set a new value, all the values change.
StopsOnRoute.h
#interface StopsOnRoutes : NSObject
#property (nonatomic) NSUInteger start_route_id;
#property (nonatomic) NSUInteger start_stop_id;
#property (nonatomic) NSUInteger start_time;
#end
FirstViewController.m
- (void)viewDidLoad
{
NSMutableArray *route1 = [[NSMutableArray alloc] init];
StopsOnRoutes *stopOnRoutes = [[StopsOnRoutes alloc] init];
int p_time = 0;
int p_route = 0;
int p_stop = 0;
while(p_time<10){
p_time = p_time + 1;
p_route = p_route + 1;
p_stop = p_stop + 1;
[stopOnRoutes setStart_time:p_time];
[stopOnRoutes setStart_route_id:p_route];
[stopOnRoutes setStart_stop_id:p_stop];
[route1 addObject:stopOnRoutes];
}
}
Unexpected output of array route1:
10 | 10 | 10
10 | 10 | 10
10 | 10 | 10
10 | 10 | 10
10 | 10 | 10
10 | 10 | 10
10 | 10 | 10
10 | 10 | 10
10 | 10 | 10
10 | 10 | 10
Expected output of array route1:
1 | 1 | 1
2 | 2 | 2
3 | 3 | 3
4 | 4 | 4
5 | 5 | 5
6 | 6 | 6
7 | 7 | 7
8 | 8 | 8
9 | 9 | 9
10 | 10 | 10
You are reusing the same object instance over and over. Create a new one each time in the loop.
while(p_time<10){
StopsOnRoutes *stopOnRoutes = [[StopsOnRoutes alloc] init];
p_time = p_time + 1;
p_route = p_route + 1;
p_stop = p_stop + 1;
[stopOnRoutes setStart_time:p_time];
[stopOnRoutes setStart_route_id:p_route];
[stopOnRoutes setStart_stop_id:p_stop];
[route1 addObject:stopOnRoutes];
}

VirtualTreeView: Edit next column

How can I configure a virtual tree view to edit the next column when user presses TAB?
+--------+-----------+
+ |1 + |2 +
+--------+-----------+
+ + +
+--------+-----------+
Default behaviour is editing the next node/row:
+--------+-----------+
+ |1 + +
+--------+-----------+
+ |2 + +
+--------+-----------+
I would suggest setting up the 'OnKeyPress' event and then manually directing the selected item in the treeview to the desired next item.

Resources