개요

ConstraintsTransformBox는 부모로부터 받은 제약 조건을 변환하여 자식에게 전달하는 위젯입니다. 이를 통해 자식 위젯이 받는 제약 조건을 동적으로 수정할 수 있습니다.

참조: https://api.flutter.dev/flutter/widgets/ConstraintsTransformBox-class.html

언제 사용하나요?

  • 자식 위젯이 받는 제약 조건을 커스터마이즈해야 할 때
  • 스크롤 가능한 영역에서 자식이 무한 높이를 가지도록 할 때
  • 특정 차원의 제약을 일시적으로 해제해야 할 때
  • 복잡한 레이아웃에서 제약 조건을 디버깅할 때
  • UnconstrainedBox보다 더 세밀한 제어가 필요할 때

기본 사용법

// 모든 제약 제거
ConstraintsTransformBox({
  constraintsTransform: ConstraintsTransformBox.unconstrained,
  child: Container({
    width: 300,
    height: 300,
    color: 'blue'
  })
})

// 높이 제약만 제거
ConstraintsTransformBox({
  constraintsTransform: ConstraintsTransformBox.heightUnconstrained,
  child: Column({
    children: [
      Text('자유로운 높이'),
      // ... 많은 자식들
    ]
  })
})

// 커스텀 변환
ConstraintsTransformBox({
  constraintsTransform: (constraints) => {
    return new Constraints({
      minWidth: Math.max(constraints.minWidth, 100),
      maxWidth: constraints.maxWidth,
      minHeight: 0,
      maxHeight: Infinity
    });
  },
  child: child
})

Props

constraintsTransform (필수)

값: (constraints: Constraints) => Constraints

부모로부터 받은 제약 조건을 변환하는 함수입니다. 이 함수는 원본 제약 조건을 받아 새로운 제약 조건을 반환해야 합니다.

ConstraintsTransformBox({
  constraintsTransform: (constraints) => {
    // 최소 너비를 200으로 설정
    return constraints.copyWith({
      minWidth: 200
    });
  },
  child: child
})

child (선택)

값: Widget | undefined

변환된 제약 조건이 적용될 자식 위젯입니다.

alignment (선택)

값: Alignment (기본값: Alignment.center)

자식의 크기가 부모와 다를 때 자식을 정렬하는 방법입니다.

ConstraintsTransformBox({
  constraintsTransform: ConstraintsTransformBox.unconstrained,
  alignment: Alignment.topLeft,
  child: Container({
    width: 100,
    height: 100,
    color: 'red'
  })
})

clipped (선택)

값: boolean (기본값: false)

자식이 부모의 경계를 벗어날 때 클리핑할지 여부입니다.

ConstraintsTransformBox({
  constraintsTransform: ConstraintsTransformBox.unconstrained,
  clipped: true,  // 오버플로우 클리핑
  child: Container({
    width: 500,
    height: 500,
    color: 'green'
  })
})

textDirection (선택)

값: TextDirection (기본값: TextDirection.ltr)

정렬을 해석하는 데 사용되는 텍스트 방향입니다.

정적 헬퍼 메서드

ConstraintsTransformBox는 일반적인 변환을 위한 여러 정적 메서드를 제공합니다:

// 제약 조건을 변경하지 않음
ConstraintsTransformBox.unmodified

// 모든 제약 제거 (무한 크기)
ConstraintsTransformBox.unconstrained

// 너비 제약만 제거
ConstraintsTransformBox.widthUnconstrained

// 높이 제약만 제거
ConstraintsTransformBox.heightUnconstrained

// 최대 높이 제약 제거
ConstraintsTransformBox.maxHeightUnconstrained

// 최대 너비 제약 제거
ConstraintsTransformBox.maxWidthUnconstrained

// 최대 너비와 높이 제약 제거
ConstraintsTransformBox.maxUnconstrained

실제 사용 예제

예제 1: 스크롤 가능한 리스트에서 높이 제약 제거

const ScrollableList = ({ items }) => {
  return SingleChildScrollView({
    child: ConstraintsTransformBox({
      constraintsTransform: ConstraintsTransformBox.heightUnconstrained,
      child: Column({
        children: items.map(item => 
          ListTile({
            title: Text(item.title),
            subtitle: Text(item.description)
          })
        )
      })
    })
  });
};

예제 2: 최소 크기 보장하면서 제약 변환

const MinSizeTransform = ({ minSize = 150, child }) => {
  return ConstraintsTransformBox({
    constraintsTransform: (constraints) => {
      return new Constraints({
        minWidth: Math.max(constraints.minWidth, minSize),
        maxWidth: constraints.maxWidth,
        minHeight: Math.max(constraints.minHeight, minSize),
        maxHeight: constraints.maxHeight
      });
    },
    child: child
  });
};

// 사용
MinSizeTransform({
  minSize: 200,
  child: Container({
    color: 'blue',
    child: Text('최소 200x200 크기 보장')
  })
})

예제 3: 종횡비를 유지하면서 제약 변환

const AspectRatioTransform = ({ aspectRatio = 1, child }) => {
  return ConstraintsTransformBox({
    constraintsTransform: (constraints) => {
      const width = constraints.maxWidth;
      const height = width / aspectRatio;
      
      return new Constraints({
        minWidth: 0,
        maxWidth: width,
        minHeight: 0,
        maxHeight: height
      });
    },
    alignment: Alignment.center,
    child: child
  });
};

예제 4: 디버깅용 제약 로깅

const DebugConstraints = ({ label, child }) => {
  return ConstraintsTransformBox({
    constraintsTransform: (constraints) => {
      console.log(`${label} 제약:`, {
        minWidth: constraints.minWidth,
        maxWidth: constraints.maxWidth,
        minHeight: constraints.minHeight,
        maxHeight: constraints.maxHeight
      });
      
      return constraints;  // 변경 없이 반환
    },
    child: child
  });
};

// 사용
DebugConstraints({
  label: 'Container',
  child: Container({
    width: 200,
    height: 200,
    color: 'red'
  })
})

예제 5: 조건부 제약 변환

const ConditionalConstraints = ({ 
  isExpanded, 
  maxWidth = 300,
  child 
}) => {
  return ConstraintsTransformBox({
    constraintsTransform: (constraints) => {
      if (isExpanded) {
        return constraints;  // 확장 모드에서는 원본 제약 사용
      }
      
      // 축소 모드에서는 최대 너비 제한
      return constraints.copyWith({
        maxWidth: Math.min(constraints.maxWidth, maxWidth)
      });
    },
    clipped: !isExpanded,
    child: AnimatedContainer({
      duration: Duration({ milliseconds: 300 }),
      child: child
    })
  });
};

제약 변환 패턴

일반적인 변환 패턴

// 1. 최소 크기 강제
(constraints) => constraints.copyWith({
  minWidth: 100,
  minHeight: 100
})

// 2. 최대 크기 제한
(constraints) => constraints.copyWith({
  maxWidth: Math.min(constraints.maxWidth, 500),
  maxHeight: Math.min(constraints.maxHeight, 500)
})

// 3. 정사각형 강제
(constraints) => {
  const size = Math.min(constraints.maxWidth, constraints.maxHeight);
  return Constraints.tight({ width: size, height: size });
}

// 4. 비율 유지
(constraints) => {
  const ratio = 0.5; // 높이가 너비의 절반
  return constraints.copyWith({
    maxHeight: constraints.maxWidth * ratio
  });
}

주의사항

  • 변환된 제약이 유효하지 않으면 레이아웃 오류가 발생할 수 있습니다
  • 무한 제약을 사용할 때는 자식이 고유 크기를 가져야 합니다
  • clipped가 false일 때 자식이 부모를 오버플로우할 수 있습니다
  • 너무 복잡한 변환은 레이아웃 성능에 영향을 줄 수 있습니다
  • 변환 함수는 순수 함수여야 하며, 부작용이 없어야 합니다

관련 위젯

  • UnconstrainedBox: 모든 제약을 제거하는 간단한 방법
  • ConstrainedBox: 추가 제약을 적용
  • OverflowBox: 부모 제약을 벗어날 수 있게 허용
  • SizedBox: 고정 크기 지정
  • FractionallySizedBox: 부모 크기의 비율로 크기 지정