일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 프로그래머스
- react native lodash
- javascript interface
- react circle progress
- 리액트네이티브
- Graveyard Keeper
- 하우스플리퍼
- 리액트 line chart
- 프로그래머스 Lv0
- Kotlin
- 프로그래머스 LV.0
- react circle progress bar
- react native jsi
- 오블완
- RecyclerView
- react native hook
- 스팀게임추천
- react native hooks
- 리액트네이티브 hooks
- 리액트 라인차트
- Android
- react
- React Native
- react line chart
- 안드로이드
- 하우스플리퍼인테리어
- 티스토리챌린지
- react 라인차트
- circular progress bar
- ReactNative
- Today
- Total
숨참고 개발다이브
[React] 리액트 원형 프로그래스 (Circle Progress Bar) 컴포넌트 만들기/예제 본문
[React] 리액트 원형 프로그래스 (Circle Progress Bar) 컴포넌트 만들기/예제
뚀니 Ddoeni 2024. 11. 4. 15:48
이런 식으로 생긴 원형 Progress는 자주 사용되는 디자인 요소 중 하나이다.
이런 프로그래스 컴포넌트를 라이브러리가 아닌, 직접 커스텀할 수 있는 컴포넌트로 생성해 보았다.
게시글에 올라가는 코드는 React 프로젝트이지만, 애니메이션 부분을 React Native에서 제공하는 Animated를 활용하여 Path 컴포넌트에 애니메이션을 적용하면 동일하게 작동된다.
전체 코드의 완성본은 다음과 같다.
반지름과 수치를 조절할 수 있는 range bar를 <input> 태그를 활용해 생성하였고, react-color라는 괜찮은 라이브러리가 있어 색상 피커도 추가해보았다.
포스팅에서는 가장 중요한 CircleProgress 컴포넌트에 대해서만 설명하도록 한다.
CircleProgress.tsx
import { animated, useSpring } from "react-spring";
const PROGRESS_MIN_PERCENTAGE = 0;
const PROGRESS_MAX_PERCENTAGE = 1;
interface CircleProgressProps {
progress: number;
radius: number;
strokeWidth: number;
strokeColor: string;
trackColor: string;
}
const CircleProgress = (props: CircleProgressProps) => {
const { progress, radius, strokeWidth, strokeColor, trackColor } = props;
const circumference = 2 * Math.PI * radius;
const clampedProgress = Math.min(
Math.max(progress, PROGRESS_MIN_PERCENTAGE),
PROGRESS_MAX_PERCENTAGE
);
const { animatedValue } = useSpring({
animatedValue: clampedProgress,
config: { duration: 800 },
});
return (
<div>
<svg height={radius * 2 + strokeWidth} width={radius * 2 + strokeWidth}>
<g
transform={`translate(${radius + strokeWidth / 2}, ${
radius + strokeWidth / 2
})`}
>
<circle
r={radius}
fill={"#ffffff"}
stroke={trackColor}
strokeWidth={strokeWidth}
strokeLinecap="round"
/>
<animated.path
fill={"transparent"}
stroke={strokeColor}
strokeWidth={strokeWidth}
strokeDasharray={circumference}
strokeDashoffset={animatedValue.to((v) => circumference * (1 - v))}
d={`M0,-${radius} A${radius},${radius} 0 1,0 0,${radius} A${radius},${radius} 0 1,0 0,-${radius}`}
/>
</g>
</svg>
</div>
);
};
export default CircleProgress;
해당 컴포넌트는 progress 수치, 반지름 및 차트의 색상을 속성값으로 받아 자유롭게 변형이 가능하도록 작성하였다.
const { animatedValue } = useSpring({
animatedValue: clampedProgress,
config: { duration: 800 },
});
- useSpring: react-spring에서 제공하는 애니메이션 기능으로, 숫자나 색상 등 특정 값을 점진적으로 변화시키기 위해 사용되었다. useSpring을 사용하여 clampedProgress 값을 부드럽게 변화시켜 원형 진행 바의 애니메이션을 생성해 주었다.
- animatedValue: 여기서 animatedValue는 clampedProgress 값을 기준으로 변화하는 애니메이션 값이다. 예를 들어 clampedProgress 값이 0.5일 경우, animatedValue가 0에서 0.5로 점진적으로 변경되며, 이 값을 활용해 원형 진행 바의 애니메이션 효과를 줄 수 있다.
- config: config 속성은 애니메이션 설정을 정의하는 부분으로 { duration: 800 }은 애니메이션이 800밀리초 동안 지속되도록 설정한다.
만약, RN 환경에서 해당 코드를 사용한다면 Animated.createAnimatedComponent(Path)로 AnimatedPath를 생성해 주고, useRef를 활용해 애니메이션 초기값을 생성하여 Path 컴포넌트의 strokeDashoffset에 값을 적용해 주면 된다. Animated.timing() 등의 원하는 애니메이션 동작을 원하는 실행 시점에 코드를 작성해 주면 된다.
<g
transform={`translate(${radius + strokeWidth / 2}, ${
radius + strokeWidth / 2
})`}
>
transform="translate(x, y)" 형태로 지정된 translate 변환은 그룹 내의 모든 요소를 지정된 x, y 좌표만큼 이동시키는 것을 의미한다.
코드에서는 x와 y 값은 radius + strokeWidth / 2로 계산되는데, 반지름과 stroke 두께를 고려하여 원형 경로가 중앙에 위치하도록 설정하는 것이다.
transform={translate(${radius + strokeWidth / 2}, ${radius + strokeWidth / 2})}는 SVG 내에서 원의 중심점이 (0, 0) 대신 (radius + strokeWidth / 2, radius + strokeWidth / 2)로 이동되도록 해주는 것을 의미한다. 이렇게 하면 <g> 그룹 내의 모든 요소가 중앙에 맞춰진다.
<circle
r={radius}
fill={"#ffffff"}
stroke={trackColor}
strokeWidth={strokeWidth}
strokeLinecap="round"
/>
<circle> 은 뒤쪽에 표시될 원(회색 트랙)을 나타낸다. 트랙은 항상 원 전체를 그리기 때문에 <path>를 사용하지 않았다. 해당 컴포넌트에 stroke와 strokeWidth 속성을 주어 테두리를 나타내고, fill로 배경 색상을 설정한다. 투명한 배경을 원한다면 'transparent'를 적용하면 된다.
<animated.path
fill={"transparent"}
stroke={strokeColor}
strokeWidth={strokeWidth}
strokeDasharray={circumference}
strokeDashoffset={animatedValue.to((v) => circumference * (1 - v))}
d={`M0,-${radius} A${radius},${radius} 0 1,0 0,${radius} A${radius},${radius} 0 1,0 0,-${radius}`}
/>
- strokeDasharray: 원형 경로를 따라 선의 길이를 설정해 주는 속성이다. 해당 코드에서는 strokeDasharray={circumference}는 전체 원의 둘레(circumference)를 사용한다. strokeDashoffset과 함께 사용하면 선의 일부만 보이게 만들어 진행 표시 효과를 줄 수 있다.
- strokeDashoffset: strokeDasharray에 의해 정의된 선의 시작 위치를 조정하여, 애니메이션 효과로 진행 상태를 표시한다. animatedValue는 0에서 1 사이의 진행 값을 가진다. 이 값을 circumference * (1 - v)로 계산하여 strokeDashoffset에 적용함으로써 선의 길이를 조절한다.
- d: SVG 경로를 지정하며, 해당 코드에서는 원형 경로를 그리기 위해 시작점과 두 개의 반원을 연결하여 완전한 원을 만든다.
- d={M0,-${radius} A${radius},${radius} 0 1,0 0,${radius} A${radius},${radius} 0 1,0 0,-${radius}}
- M0,-${radius}: 경로의 시작점. Path는 (0, -radius) 위치에서 시작한다.
- A${radius},${radius} 0 1,0 0,${radius}: 아크(호)를 그리는 명령. 반지름이 radius인 원을 그리며, 시작점에서 반원을 아래 방향으로 그리는 것을 나타낸다.
- A${radius},${radius} 0 1,0 0,-${radius}: 두 번째 반원을 그리며 원을 완성한다.
이렇게 기본 Circle Progress Bar 컴포넌트를 생성해 보았다.
전체 코드는 여기서 확인 가능!
'개발 > React & React Native' 카테고리의 다른 글
[React] 리액트 라인차트 (Line Chart) 컴포넌트 만들기 (1) | 2024.11.08 |
---|---|
[React Native] React Native의 New Architecture (JSI, JavaScript Interface) (5) | 2024.10.31 |
[React Native] React Native의 구 Bridge 아키텍쳐(Architecture) (3) | 2024.10.29 |
[React Native/iOS] 리액트 네이티브 환경에서 iOS Privacy Manifest 정책 대응하기 (0) | 2024.03.25 |
[React Native] patch-package를 사용해 라이브러리 커스텀하기 (0) | 2024.03.19 |