ios - How to prevent "bounce" effect when a custom view redraws after zooming? -


note casual readers: despite title, question has nothing uiscrollview properties bounces (scrolling related) or bounceszoom.

i using uiscrollview add zooming custom view. custom view uses sublayers draw content. each sublayer calayer instance added view's main layer [calayer addsublayer:]. sublayers use coregraphics render content.

after each zoom completes, custom view needs redraw content @ new zoom scale content appears crisp , sharp again. trying approach work shown in this question, i.e. reset scroll view's zoomscale property 1.0 after each zoom operation, adjust minimumzoomscale , maximumzoomscale properties user cannot zoom in/out more intended.

the content redrawing works correctly (!), missing smooth gui update zoomed content redrawn in place without appearing move. current solution (code example follows @ bottom of question), observe kind of "bounce" effect: zoom operation ends, zoomed content briefly moves different location, moves original location.

i not entirely sure reason "bounce" effect is: either there 2 gui update cycles (one resetting zoomscale 1.0, , setneedsdisplay), or sort of animation taking place makes both changes visible, 1 after other.

my question is: how can prevent "bounce" effect described above?

update: following minimal complete code example can copy&paste observe effect talking about.

  1. create new xcode project using "empty application" template.
  2. add code below appdelegate.h , appdelegate.m, respectively.
  3. in project's link build phase, add reference quartzcore.framework.

stuff goes appdelegate.h:

#import <uikit/uikit.h>  @class layerview;  @interface appdelegate : uiresponder <uiapplicationdelegate, uiscrollviewdelegate> @property (nonatomic, retain) uiwindow* window; @property (nonatomic, retain) layerview* layerview; @end 

stuff goes appdelegate.m:

#import "appdelegate.h" #import <quartzcore/quartzcore.h>  @class layerdelegate;  @interface layerview : uiview @property (nonatomic, retain) layerdelegate* layerdelegate; @end  @interface layerdelegate : nsobject @property(nonatomic, retain) calayer* layer; @property (nonatomic, assign) cgfloat zoomscale; @end  static cgfloat kminimumzoomscale = 1.0; static cgfloat kmaximumzoomscale = 5.0;  @implementation appdelegate  - (void) dealloc {   self.window = nil;   self.layerview = nil;   [super dealloc]; }  - (bool) application:(uiapplication*)application didfinishlaunchingwithoptions:(nsdictionary*)launchoptions {   [uiapplication sharedapplication].statusbarhidden = yes;   self.window = [[[uiwindow alloc] initwithframe:[[uiscreen mainscreen] bounds]] autorelease];   self.window.backgroundcolor = [uicolor whitecolor];    uiscrollview* scrollview = [[[uiscrollview alloc] initwithframe:self.window.bounds] autorelease];   [self.window addsubview:scrollview];   scrollview.contentsize = scrollview.bounds.size;   scrollview.delegate = self;   scrollview.minimumzoomscale = kminimumzoomscale;   scrollview.maximumzoomscale = kmaximumzoomscale;   scrollview.zoomscale = 1.0f;   scrollview.bounceszoom = no;    self.layerview = [[[layerview alloc] initwithframe:scrollview.bounds] autorelease];   [scrollview addsubview:self.layerview];    [self.window makekeyandvisible];   return yes; }  - (uiview*) viewforzoominginscrollview:(uiscrollview*)scrollview {   return self.layerview; }  - (void) scrollviewdidendzooming:(uiscrollview*)scrollview withview:(uiview*)view atscale:(float)scale {   cgpoint contentoffset = scrollview.contentoffset;   cgsize contentsize = scrollview.contentsize;    scrollview.maximumzoomscale = scrollview.maximumzoomscale / scale;   scrollview.minimumzoomscale = scrollview.minimumzoomscale / scale;   // big change here: resets scroll view's contentsize ,   // contentoffset, , layerview's frame, bounds , transform   // properties   scrollview.zoomscale = 1.0f;    cgfloat newzoomscale = self.layerview.layerdelegate.zoomscale * scale;   self.layerview.layerdelegate.zoomscale = newzoomscale;    self.layerview.frame = cgrectmake(0, 0, contentsize.width, contentsize.height);   scrollview.contentsize = contentsize;   [scrollview setcontentoffset:contentoffset animated:no];    [self.layerview setneedsdisplay]; }  @end  @implementation layerview  - (id) initwithframe:(cgrect)frame {   self = [super initwithframe:frame];   if (self)   {     self.layerdelegate = [[[layerdelegate alloc] init] autorelease];     [self.layer addsublayer:self.layerdelegate.layer];     // super's initwithframe invoked setneedsdisplay, need     // repeat because @ time our layerdelegate property still empty     [self setneedsdisplay];    }   return self; }  - (void) dealloc {   self.layerdelegate = nil;   [super dealloc]; }  - (void) setneedsdisplay {   [super setneedsdisplay];   // zooming changes view's frame, not frame of layer   self.layerdelegate.layer.frame = self.bounds;   [self.layerdelegate.layer setneedsdisplay]; }  @end  @implementation layerdelegate  - (id) init {   self = [super init];   if (self)   {     self.layer = [calayer layer];     self.layer.delegate = self;     self.zoomscale = 1.0f;   }   return self; }  - (void) dealloc {   self.layer = nil;   [super dealloc]; }  - (void) drawlayer:(calayer*)layer incontext:(cgcontextref)context {   cgrect layerrect = self.layer.bounds;   cgfloat radius = 25 * self.zoomscale;   cgfloat centerdistancefromedge = 5 * self.zoomscale + radius;    cgpoint topleftcenter = cgpointmake(cgrectgetminx(layerrect) + centerdistancefromedge,                                       cgrectgetminy(layerrect) + centerdistancefromedge);   [self drawcirclewithcenter:topleftcenter radius:radius fillcolor:[uicolor redcolor] incontext:context];    cgpoint layercenter = cgpointmake(cgrectgetmidx(layerrect), cgrectgetmidy(layerrect));   [self drawcirclewithcenter:layercenter radius:radius fillcolor:[uicolor greencolor] incontext:context];    cgpoint bottomrightcenter = cgpointmake(cgrectgetmaxx(layerrect) - centerdistancefromedge,                                           cgrectgetmaxy(layerrect) - centerdistancefromedge);   [self drawcirclewithcenter:bottomrightcenter radius:radius fillcolor:[uicolor bluecolor] incontext:context]; }  - (void) drawcirclewithcenter:(cgpoint)center                        radius:(cgfloat)radius                     fillcolor:(uicolor*)color                     incontext:(cgcontextref)context {   const int startradius = [self radians:0];   const int endradius = [self radians:360];   const int clockwise = 0;   cgcontextaddarc(context, center.x, center.y, radius,                   startradius, endradius, clockwise);   cgcontextsetfillcolorwithcolor(context, color.cgcolor);   cgcontextfillpath(context); }  - (double) radians:(double)degrees {   return degrees * m_pi / 180; }  @end 

based on sample project, key you're manipulating calayer directly. default, setting calayer properties, such frame, cause animations. suggestion use [uiview setanimationsenabled:no] on right track, affects uiview-based animations. if calayer equivalent, in setneedsdisplay: method:

[catransaction begin]; [catransaction setdisableactions:yes]; self.layerdelegate.layer.frame = self.bounds; [catransaction commit]; 

it prevents implicit frame-changing animation , looks right me. can disable these implicit animations via calayerdelegate method in layerdelegate class:

- (id<caaction>)actionforlayer:(calayer *)layer forkey:(nsstring *)event {     return (id)[nsnull null]; // nsnull means "don't implicit animations" } 

original suggestions:

perhaps in animation block without knowing it? or, perhaps 1 of methods you're calling setting animation block? if [uiview setanimationsenabled:no] before code , re-enable them after?

if it's not animation, it's suspect; 2 view updates of kind. (perhaps 1 scroll view, , 1 code somehow?) runnable sample code great in case.

(out of curiosity, have tried using calayer's shouldrasterize , rasterizationscale rather faking out zoom level?)


Comments

Popular posts from this blog

get url and add instance to a model with prefilled foreign key :django admin -

css - Make div keyboard-scrollable in jQuery Mobile? -

ruby on rails - Seeing duplicate requests handled with Unicorn -