Jetpack Compose의 소수 테이블 생성기

나는 이미 6년여 동안 이 소수표 생성기의 원시 버전을 쓴 적이 없다.그것은 내가 대학 1학기에 C와 SDL을 공부한 후 나의 코딩 경력의 시작이었다.원본 프로젝트is available here의 아카이브 버전120 lines of excellent C code.

전제 조건


간단하게 위에서 링크한 글을 돌이켜 보면 이 프로젝트의 목적은 직관적이고 간결한 소수 표시를 만드는 것이다.최초의 종이 버전에는 최대 4000개의 소수가 포함되어 있는데, 보기에 다음과 같다.

그것은 어떻게 일합니까?각 블록은 열 개의 숫자로 구성된 블록을 대표한다.소수(2이상)는 숫자 1, 3, 7 또는 9에서만 끝날 수 있기 때문에 정사각형의 각 각은 주어진 끝 숫자가 10번 너비 블록 안의 소수인지 여부를 표시할 수 있다.

예를 들어 표의 세 번째 블록은 숫자 21-30에 대응하고 두 개의 연결된 각은 23과 29만이 이 범위 내의 소수임을 나타낸다.
이제 안드로이드를 위한 코드를 작성합시다!

You can find the code for the completed project on GitHub.


메쉬 작성


the previous Jetpack Compose article on this blog에서 우리는 아래에서 위로 애니메이션 시계를 만들었다.이번에는 위에서 아래로 디자인을 하고 Compose에서 격자를 렌더링하는 것부터 시작하겠습니다.이를 위해 실험 LazyVerticalGrid API를 사용합니다.
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Primes() {
    LazyVerticalGrid(
        modifier = Modifier // 1
            .fillMaxSize()
            .background(Color(0xFFE53935))
            .padding(8.dp),
        cells = GridCells.Fixed(10), // 2
    ) {
        items(count = 100) { // 3
            Box( 
                Modifier // 4
                    .aspectRatio(1f)
                    .padding(1.dp)
                    .background(Color.DarkGray)
            )
        }
    }
}
위의 코드를 분해하려면 다음과 같이 하십시오.
  • 조합된LazyVerticalGrid 전체 화면에 빨간색 배경과 약간의 채우기가 있습니다.
  • 열 수가 고정된 메쉬를 표시합니다.
  • 메쉬에는 100개의 항목이 포함됩니다.
  • 항목마다 간단한 Box로 시작하여 정사각형으로 제한되어 약간의 충전과 짙은 색의 배경색이 있다.
  • Note how we had to opt-in to using the experimental API with the @OptIn annotation, which also requires some additional project-level configuration to enable it. You can read more about this language feature in Mastering API Visibility in Kotlin.


    위 코드를 실행하면 정사각형 격자가 스크롤 가능으로 표시됩니다.

    정사각형


    격자 항목마다 PrimeSquare 조합을 만들 수 있도록 재구성해 봅시다.이것은 현재 편이량을 받아들일 것입니다. 소수를 보여야 합니다.
    @OptIn(ExperimentalFoundationApi::class)
    @Composable
    fun Primes() {
        LazyVerticalGrid(...) {
            items(count = 100) { index ->
                PrimeSquare(offset = index * 10)
            }
        }
    }
    
    @Composable
    fun PrimeSquare(offset: Int) {
        Box(
            Modifier
                .aspectRatio(1f)
                .padding(1.dp)
                .background(Color.DarkGray)
        ) {
            CornerLine()
        }
    }
    
    단일PrimeSquare의 경우 왼쪽 상단에서 중심까지의 한 줄만 렌더링하고 우리만의CornerLine 조합을 사용합니다.Dell은 Canvas API를 사용하여 Compose에서 이러한 이점을 실현할 수 있습니다.
    @Composable
    fun CornerLine() {
        Canvas(Modifier.fillMaxSize()) {
            drawLine(
                color = Color.White,
                start = Offset.Zero,
                end = Offset(size.width / 2, size.height / 2),
                strokeWidth = 2.dp.toPx(),
            )
        }
    }
    
    이것은 우리에게 다음과 같은 인상을 주었다. 좋은 시작이었다.

    사각형 회전 및 스택


    이 선이 정확한 구석에 들어가도록 우리는 캔버스에 그림을 그리는 동시에 캔버스를 회전시킬 수 있다.간단한 rotate 함수 호출이 이 문제를 해결해 주었다.우리는 회전량을 CornerLine의 매개 변수로 삼을 것이다.
    @Composable
    fun CornerLine(degrees: Float) {
        Canvas(Modifier.fillMaxSize()) {
            rotate(degrees) {
                drawLine(
                    color = Color.White,
                    start = Offset.Zero,
                    end = Offset(size.width / 2, size.height / 2),
                    strokeWidth = 2.dp.toPx(),
                )
            }
        }
    }
    
    이 작업을 매우 간단하게 처리하기 위해 각 각도의 이름을 조합하여 적절한 회전을 만듭니다.
    @Composable fun One() = CornerLine(degrees = 0f)
    @Composable fun Three() = CornerLine(degrees = -90f)
    @Composable fun Seven() = CornerLine(degrees = -180f)
    @Composable fun Nine() = CornerLine(degrees = -270f)
    
    우리는 어느 수가 소수인지 알아야 한다. 이를 위해 우리는 매우 기본적인 실현을 사용할 것이다.
    fun Int.isPrime(): Boolean {
        if (this < 2) return false
        return (2 until this).none { this % it == 0 }
    }
    

    Have a shorter implementation for this that's at least as correct for checking primes?


    현재 우리는 하나의 숫자가 소수인지 아닌지를 검사할 수 있고 각 각에 선을 그릴 수 있으며 우리는 간단하게 실현할 수 있다PrimeSquare:
    @Composable
    fun PrimeSquare(offset: Int) {
        Box(
            Modifier
                .aspectRatio(1f)
                .padding(1.dp)
                .background(Color.DarkGray)
        ) {
            if ((offset + 1).isPrime()) One()
            if ((offset + 3).isPrime()) Three()
            if ((offset + 7).isPrime()) Seven()
            if ((offset + 9).isPrime()) Nine()
        }
    }
    
    물론 우리가 여기에 화포를 쌓는 방식이 완전히 가장 좋은 것은 아니지만, 용기로서의 작업 원리를 잘 보여 준다.만약 우리가 소수 계산을 한 단계 낮추면, 우리는 캔버스에 모든 선을 그려서 더욱 좋은 성능을 얻을 수 있다. 이것을 연습으로 삼으려고 시도할 수 있다.
    그럼에도 불구하고 Dell의 비최적 구축 효과는 다음과 같습니다.

    마지막 윤색


    우리의 렌더링에는 두 가지 문제가 있습니다. 위의 그림을 자세히 살펴보면 이 두 가지 문제를 발견할 수 있습니다.
  • 그리는 선의 끝은 회색 상자 밖으로 확장됩니다.
  • 중간에 교차하는 선이 예상대로 교차하지 않습니다.
  • 첫 번째 질문은 조합 가능한 클립의 Box를 테두리로 설정할 수 있습니다.
    Box(
        Modifier
            .aspectRatio(1f)
            .padding(1.dp)
            .background(Color.DarkGray)
            .clipToBounds()
    ) { ... }
    
    선이 중간에 더 많이 겹치도록 우리는 그것들을 약간 길게 그릴 수 있을 것 같다Box.
    end = Offset(size.width / 2 + 2f, size.height / 2 + 2f),
    
    이 프로그램을 다시 실행하면 최종 결과가 나올 것입니다.

    결론


    마찬가지로 이 프로젝트의 전체 출처는 사용할 수 있다on GitHub.
    더 많은 유사한 작성 내용을 찾고 있는 경우 다음 기사를 참조하십시오.
  • Compose O'Clock

  • Build an Android Chat app with Jetpack Compose
  • 좋은 웹페이지 즐겨찾기