본문 바로가기
Android App 개발/chordbreaker

그래픽스 - 지판 그리기

by 시샐 2022. 10. 12.

가로 화면에 기타 지판 형상을 그려야하므로 안드로이드의 그래픽스에 대해 배워야 할 시간이 되었다.

초짜로서 아는게 없기 때문에 언제나 처럼 먼저 유튜브 영상을 참고 하기로 했는데,

아래 링크의 영상이 레이더에 걸려들었다.

 

https://www.youtube.com/watch?v=4Mo2rVOgn4M

 

 

빈 화면에 LinearLayout을 설정해두고 그 안에 빨간색 정사각형을 그리는 방법을 설명하는 간단한 영상이다.

일단 MainActivity에 영상에서와 같은 코드를 쳐넣어서 확인해보기로 했다.

 

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Paint paint = new Paint();
        paint.setColor(Color.parseColor(("#da4747")));

        Bitmap bg = Bitmap.createBitmap(800,480, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bg);
        canvas.drawRect(50,50,200,200, paint);

        LinearLayout ll = findViewById(R.id.rect);
        ll.setBackground(new BitmapDrawable(bg));
    }
}
 

 

실행을 해보았는데,

살짝 걱정했던대로 Aspect Ratio 문제 때문인지 가로로 살짝 더 긴 박스가 출력되었다.

 

 

 

이미지의 좌표나 절대 크기 값 등을 그대로 주면 문제가 될 수 있을 것 같은데,

자세한 것은 차차 알아보기로 하고,

일단 위의 코드를 참고로 해서 기타 지판과 같은 형태를 그려보기로 했다.

 

기타 줄은 6 개이므로 6 개의 라인을 그리면 될 듯하다.

7 현이나 8 현 같은 종류는 생각하지 않기로 했다.

개인적으로 싸구려 7 현 기타를 하나 가지고 있기는 하지만...

 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Paint paint = new Paint();
        paint.setColor(Color.parseColor(("#101010")));

        Bitmap bg = Bitmap.createBitmap(1400,480, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bg);

        for(int i=0;i<6;i++){
            canvas.drawLine(100,100+30*i,1300,100+30*i, paint);
        }
        canvas.drawRect(100,100,120,250, paint);

        for(int i=1;i<12;i++){
            canvas.drawLine(120+100*i,100,120+100*i,250, paint);
        }

        LinearLayout ll = findViewById(R.id.rect);
        ll.setBackground(new BitmapDrawable(bg));
    }
 

 

ㅓㅜㅑ, 비슷한게 나왔다

 

 

라인 두께 같은 것을 좀 조정해야 할 듯 싶다.

 

 

[ 삼각형 그리는 법 - path]

기타 지판은 어찌 그렸는데 라인의 두께가 너무 가는 것 같다.

다시 검색을 때려보니 이런 함수를 쓰라고 한다.

public void setStrokeWidth (float width)
 

파라미터로 0을 넘기면 헤어라인 모드를 사용하는데

헤어라인은 캔버스의 매트릭스와는 무관하게 항상 1 픽셀을 사용하여 라인을 그리는 모드라고 한다.

캔바스의 매트릭스가 정확히 뭐지?

아마 정사각형이 찌그러지는 이유가 관계가 있을까?

 

일단 width로 1를 줘보니 별차이가 없었다.

다시 2로 하니 조금 두꺼워졌다.

일단 미적인 감각은 나중에 따지기로 하고 넘어가기로 했다.

 

기타 지판은 12 프렛부터 반복이므로 총 11개의 프렛을 표시하기로 했다.

갯수가 많으니 위치가 헷갈린다.

기타를 보면 지판의 1,3,5,7,9 프렛에 마킹이 되어 있고,

이는 다시 12 프렛부터 반복된다.

 

여기서는 지판 아랫쪽에 삼각형 표시를 하기로 하고 drawPolygon같은 함수를 찾아보았다.

그런데 Android에는 Polygon 대신 Path라는 것을 사용한다고 한다.

 

일단 Path를 사용해서 귀퉁이에 삼각형을 그려보았다.

        // draw first triangle Fret mark
        Path tripath = new Path();
        tripath.reset();
        tripath.moveTo(120, 250-20); // first point
        tripath.lineTo(120, 250); // second point
        tripath.lineTo(120+10, 250); // third point
        tripath.lineTo(120, 250-20); // return to the first point

        paint.setColor(Color.parseColor(("#505050")));
        canvas.drawPath(tripath, paint);
 

 

 

여러 개를 그려야하므로 함수로 만들어 빼고 일 단계로 마무리를 지었다.

 

    private void drawFretMark(int x, int y, Path path)
    {
        path.reset();
        path.moveTo(x, y-20); // first point
        path.lineTo(x, y);       // second point
        path.lineTo(x+15, y); // third point
        path.lineTo(x, y-20); // return to the first point
    }
 
        // draw triangle Fret mark
        Path path = new Path();
        paint.setColor(Color.parseColor(("#505050")));
        for(int i=0;i<5;i++) {
            drawFretMark(120+i*200, 250, path);
            canvas.drawPath(path, paint);
        }
        drawFretMark(120+1100, 250, path);
        canvas.drawPath(path, paint);
 

 

 

 

아쯤해서 실제 디바이스에서 테스트를 해볼 필요가 있어 폰을 연결하고 다운로드를 해봤다.

일단은 잘되는 것 같다.

 

 

 

 

[원그리기]

 

각 프렛에 음계를 표시할 원을 그릴 차례가 되었다.

canvas.drawCircle(120+50, 100, 14, paint);
 

 

찌그러진 원이 나왔다.

 

이 문제를 확인해본 결과,

LinearLayout과 setBackground()를 사용한 것 때문이라는 것을 알게 되었다.

        LinearLayout ll = findViewById(R.id.rect);
        ll.setBackground(new BitmapDrawable(bg));
 

이 대신에 ImageView와 setImageView()를 사용하면 될 것이라는 희망찬 정보를 접하게 되었다.

이를 위해서 activity_main.xml의 LinearLayout에 다음과 같이 ImageView를 추가했다.

 

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/image"
            />
    </LinearLayout>
 

setBackground()를 제거하고, 그 자리에 ImageView와 setImageBitmap()을 사용한 코드를 채워넣었다.

그랬더니,

 

 

 

Good, 원이 똑바로 나오는 것을 확인할 수 있었다.

그런데, 전체적으로 그림의 사이즈가 작아졌다.

전체적으로 사이즈를 제조정 해야 할 것 같다.

 

그런데 그림이 있는 LinearLayout의 아랫 쪽에는 다양한 버튼들이 들어가야한다.

때문에 가로 상태의 아랫쪽에 Layout을 추가하는 작업을 먼저해야 할 것 같다.

 

 

 

 

반응형