지난번 올렸던 [TouchableOpacity에 position absolute적용했을 때 먹통되는 현상 해결하기]에 이어서 왜 먹통현상이 발생했고 z-index를 1로 주면 왜 해결이 되는지에 대한 글이다.
z index의 default value는 auto로 설정되어 있으며, 기본적으로 나중에 추가된 엘리먼트가 먼저 선언된 엘리먼트 위로 올라가도록 설계되어 있다.
return <>
<A/>
<B/>
<C/>
</>
따라서 위와같이 컴포넌트가 렌더링되고 있다면 이들 사이의 상하 관계는 다음과 같이 나타낼 수 있다.
하지만 z index상에서 이러한 상하관계가 설정되어 있다고 해도 react native에서 Position은 기본적으로 relative이기 때문에 동일한 부모 컴포넌트에서 호출된 상황이라면 하나의 컴포넌트가 다른 컴포넌트를 가리는 일은 대체로 발생하지 않는다.
문제는 position을 absolute로 주었을 때 발생한다. 컴포넌트에 absolute position을 주면 기존에 공간을 차지하고 있던 레이어에서 벗어나기 때문에 다른 컴포넌트 위에 오버레이 될 수 있기 때문이다. 그렇게 되면 다른 컴포넌트에 의해 가려지거나 다른 컴포넌트를 가릴 수 있게 되는 것이다.
문제가 발생했던 코드를 재현하자면 아래와 같다.
const ChevronBtn = styled.TouchableOpacity`
position: absolute;
justify-content: center;
height: 80%;
right:0px;
`;
const App = () => {
return (
<AppBackground>
<CarouselBox>
<ChevronBtn
onPress={() => {
Alert.alert('hi');
}}>
<Image
style={{width: 20, height: 20}}
source={require('./src/forward.png')}
/>
</ChevronBtn>
<ScrollViewCarousel />
</CarouselBox>
</AppBackground>
);
};
캐러셀 영역을 지정하는 CarouselBox 컴포넌트 안쪽에 우측 화살표 버튼 하나와 캐러셀 컴포넌트가 위치하고 있다. 이 상황에서 ChevronBtn을 아무리 눌러도 "hi"라는 얼럿이 뜨지 않는 문제가 발생했었다.
그 이유는 캐러셀이 버튼보다 나중에 선언되었기 때문에, 사실상 캐러셀이 버튼을 가리고 있는 상황이기 때문이다. 그럼에도 버튼이 눈에 보였던 것은 캐러셀에 padding을 주었고, 그로인해 현재 버튼이 위치한 외곽 지역은 투명한 View가 덮고 있었던 탓이다.
실제로 캐러셀에 주었던 padding을 없애면 아래와 같이 버튼이 완전히 가려져 보이지 않는 것을 확인할 수 있다.
이제 여기서 다시 버튼 속성에 z-index 값을 1로 주면 이렇게 버튼이 가장 높은 곳까지 올라와 우리가 터치할 수 있는 상태가 되는 것이다. (z-index를 정수값으로 주면 모든 auto보다 높은 위치로 해석하기 때문)
하지만 이것보다 더 간편한 방법이 있는데, 그냥 버튼을 캐러셀보다 나중에 선언하면 된다.
const App = () => {
return (
<AppBackground>
<CarouselBox>
<ScrollViewCarousel />
<ChevronBtn
onPress={() => {
Alert.alert('hi');
}}>
<Image
style={{width: 20, height: 20}}
source={require('./src/forward.png')}
/>
</ChevronBtn>
</CarouselBox>
</AppBackground>
);
};
잘 작동한다.