본문 바로가기

Blog/Flex

move()와 x,y 속성, setActualSize() 메서드와 width, height 속성 (1)

뭐 기본적으로 UIComponent에서 move(), setActualSize() 메서드를 사용하고, sprite 나 MovieClip 같은 데서는 그냥 x, y, width, height을 직접 설정하면 된다고 막연히 생각해 왔는데요.. 왜냐고 물으시면 UIComponent 에만 저런 메서드가 있으니깐… 근데 언제 어디서 저런 메서드를 써야하는지, 속성을 직접 설정하는거랑 무슨 차이가 있는지 잘 모르겠더란 겁니다. ( 솔직히 별 차이를 못느끼겠고 마구잡이로 섞어썼어요ㅠㅠ).

as2.0 Component

Actionscript 2.0 으로 Component를 만들때도 저런게 있었지 하면서 그냥 속성 갖다 쓰지 저런 메서드들을 만들어 놓았을까 궁금했었습니다. 제일 먼저 떠오른 생각은 크기를 설정할 때 일반적으로width, height 을 함께 설정할 경우가 많은데 이걸 한꺼번에 세팅할수 있게 만든걸거야. 두줄보단 한줄이 좋잖아. 좀 지나서는... width, height을 설정할 때 분명히 크기를 바꾸는 무슨일이 비슷한 로직으로 일어날꺼 같은데 이걸 따로 따로 설정하게 되면 그 비슷한 일이란게 두번 중복되어 실행 되어야 하니까 쫌 비효율적이야. 그래서 아마도 setSize() 메서드로 이걸 카바한걸꺼야(흠~그래도 뭔가 확실치 않아). 여지껏 이렇게 감으로 때려잡고만 있었습니다.

as2.0 Component를 살펴보면 Flex 컴포넌트와 구조상 유사한 점이 참 많습니다.

    private function init ():Void {
        
super.init ();
        
// bounding box 를 감춘다.
        boundingBox_mc._visible = false;
        boundingBox_mc._width = boundingBox_mc._height = 0;
    }
    
private function createChildren ():Void {
    }
    
// sizing을 위해 특별히 구현할것은 없다. invalidate() 호출을 통하여 draw() 함수를 호출하는것 뿐이다.
    private function size ():Void {
        
super.size();
        invalidate ();
    }
    
// This function is called every time our component is invalidated.
    private function draw ():Void {
        
super.draw();
    }

init() à initialize(),
createChildren()
à createChildren(),
size()
à measure(),
draw()
à updateDisplayList()

각 메서드의 역할이 이 정도쯤 되지 않을까 생각됩니다. as2.0에서는 무효화 메서드가 invalidate() 메서드 하나밖에 없습니다(유효화도 마찬가지 - 플렉스에는 세개씩 있죠). 그래서 invalidate()메서드가 호출되면 그 다음에 항상 draw() 메서드가 호출되어 스크린을 업데이트하는 패턴으로 코딩이 진행됩니다. setSize() 메서드가 호출되면 내부적으로 invalidate()를 통해 draw() 메서드가 호출되는 구조인 것입니다. invalidate()로 인한 퍼포먼스 향상을 위해서 입니다.

다시 Flex컴포넌트로 돌아와서 생각해보면 같은 맥락으로 이해할 수 있을 것 같습니다.사실 찾아보면 move(), setActualSize() 메서드는 UIMovieClip이나 UITextField에도 있고, 또 플래시에서 사용하는 fl.core.UIComponent에도 move()와setSize() 메서드가 있습니다. Livedoc 도움말과 함께 사이트 군데군데 있는 조각 지식을 조합해 보니(관련글 찾기가 너무 힘들어요ㅠㅠ) 이들 메서드들은 updateDisplayList() 메서드와 관련이 많은 것 같았습니다. 사실 x, y, width, height을 직접적으로 설정하더라도 큰 무리는 없지만 대부분 오버라이딩한 updateDisplayList() 메서드에서 사용하길 권하고 있었습니다 (어라 나는 아무데서나 쓰는데…). 좀 자세히 보겠습니다. 

 width, height 속성을 직접 설정 VS setActualSize () 메서드 사용

 width와 height 값을 직접 설정할 때와는 달리 setActualSize() 메서드를 사용하면 explictWidth 와 explicitHeight 속성을 설정하지 않습니다. 컴포넌트의 setActualSize() 메서드는 layout container의 updateDisplayList() 메서드에서 호출됩니다. explictWidth, explicitHeight 속성을 설정하지 않는다는 것은 setActualSize() 메서드에서 직접적으로 크기를 변경하지는 않는다는 것을 뜻합니다.

(explictWidth에 대한 지식이 필요합니다.- 지돌스타)

아래는 UIComponent 에 구현된 코드입니다. setActualSize() 메서드는 invalidateDisplayList() 메서드르 호출한 후 바로 이벤트를 송출합니다. 반면에 width setter 함수에서는 explictWidth를 변경(실제 크기 변경)한 후 invalidateSize() 메서드를 호출합니다.

        public function setActualSize(w:Number, h:Number):void
        {
            
var changed:Boolean = false;

            
if ( _width != w ){
                _width = w;
                dispatchEvent(
new Event("widthChanged"));
                changed =
true;
            }

            
if ( _height != h ){
                _height = h;
                dispatchEvent(
new Event("heightChanged"));
                changed =
true;
            }

            
if ( changed ){
                
invalidateDisplayList();
                
dispatchResizeEvent();
            }
        }


        override public function set width(value:Number):void
        {
            
if ( explicitWidth != value ){
                
explicitWidth = value;
                
// We invalidate size because locking in width
                // may change the measured height in flow-based components.
                invalidateSize();
            }

            
if ( _width != value ){
                invalidateProperties();
                invalidateDisplayList();

                
var p:IInvalidating = parent as IInvalidating;

                
if ( p && includeInLayout ){
                    p.invalidateSize();
                    p.invalidateDisplayList();
                }

                _width = value;
                dispatchEvent(
new Event("widthChanged"));
            }
        }

아마 width, height을 직접 변경하는것은 즉각적으로 반영이 되지만 setActualSize() 메서드를 이용한 방법은 약간의 delay가 있다고 이해하면 될것 같습니다.

Flex Bug 관리 사이트에서 " Calling setActualSize() doesnt properly resize the component " 라는 문서에 다음과 같은 글이 있습니다.
( https://bugs.adobe.com/jira/browse/SDK-11404?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel )

Calling setActualSize() is typically only done by layout containers, and that is working correctly. The preferred method of changing a components size is to set width/height (or percentWidth/percentHeight), and that is working correctly.

Recommend defer. The documented way to change size is to set the width and height properties directly. This works fine. Calling setActualSize() is intended to be used by Container writers for their layout code, and this works fine too. Fixing setActualSize() to work outside of a container layout algorithm would be risky at this point in time.

width, height으로 크기를 조절하되 setActualSize() 메서드는 Container 에서 layout 계산을 위해 필요한 경우에만 사용하라는 얘긴것 같습니다.

x,y 속성을 직접 설정 VS move() 메서드 사용

LiveDoc을 보면 move() 메서드는 호출시점에 컴포넌트의 위치를 변화시키고 move event를 발생시키는 반면에 x,y 속성을 직접 설정 하는 것은 다음 번 screen이 refresh될 때 컴포넌트의 위치를 바꾸고 이벤트를 발생시킨다고 합니다. 다시 말하면 move() 메서드를 호출하면 이동 작업이 완료되는 즉시 move 이벤트 객체가 전달되는 반면, x 및 y 속성을 설정하여 컴포넌트 위치를 변경하면 다음 번에 화면 갱신 때 이벤트 객체가 전달된다는 겁니다.  

이거 왠지 width 와 setActualSize() 때와는 헷갈리는데요.. setActualSize() 는 값설정(explicitWidth) 시점과  이벤트 송출 시점이 모두 다르지만 move() 는 이벤트 송출 시점 이외엔 다른점이 없습니다. 살짝 다른것 같긴한데 깊이있게 다루지는 못하겠습니다.(여전히 헷갈림ㅠㅠ..음..도와주세요!)

        public function move(x:Number, y:Number):void
        {
            
var changed:Boolean = false;
            
if ( x != super.x ) {
                
super.x = x;
                dispatchEvent(
new Event("xChanged"));
                changed =
true;
            }
            
if ( y != super.y ) {
                
super.y = y;
                dispatchEvent(
new Event("yChanged"));
                changed =
true;
            }
            
if ( changed ) dispatchMoveEvent();
        }


        override public function set x(value:Number):void
        {
            
if ( super.x == value ) return;
            
super.x = value;
            
invalidateProperties();
            dispatchEvent(new Event("xChanged"));
        }

정리해보면, 일반적으로 (updateDisplayList() 메서드에서) 만약 children이 있고 UIComponent가 아니면 x, y, width, height을 직접 설정하고 UIComponent이면 move(), setActualSize() 메소드를 사용합니다. 나름 이렇게 정리해 보았지만 너무 부족한 감이 있네요. 다른 의견이나 자세한 내용 있으시면 트랙백으로 남겨주세요..~ 제발요~

   

'Blog > Flex' 카테고리의 다른 글

Event의 흐름 제어  (0) 2009.12.09
Flash CS4에서 폰트 임베딩  (5) 2009.12.09
UIComponent에서 살펴본 이벤트 흐름  (0) 2009.11.26
SystemManager에 대하여  (4) 2009.11.25
stage, root에 대하여  (0) 2009.11.24