본문 바로가기
안드로이드 자바

[JAVA][Android]글자크기 맞춰 drawbleStart 이미지 크기 자동조절하기

by teamnova 2024. 5. 11.
728x90

오늘은 drawableStart 속성을 활용해 뷰의 옆에 이미지를 넣었을때 그 이미지의 크기를 뷰의 글자 크기에 맞춰 자동으로 조절되게 만들어 보겠습니다.

 

 

1.drawableStart에 활용할 이미지를 만들어 둡니다. 이번에 활용할 이미지는 아래와 같이 만들었습니다.

 

 

 

2.activity_main.xml을 다음과 같이 작성해줍니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <com.example.drawablestart_example.AutoSizeDrawableEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:inputType="text"
        android:hint="입력하는 곳"
        android:drawableStart="@drawable/outline_images"
        android:drawablePadding="3dp"
        android:textSize="20sp"/>

</LinearLayout>

=> 이때 com.example.drawablestart_example.AutoSizeDrawableEditText 태그의 com.example.drawablestart_example 부분은 아래에 만들 AutoSizeDrawableEditText 클래스의 패키지 명으로 입력해주세요.

 

 

3.커스텀 edittext 클래스를 다음과 같이 작성해줍니다.

public class AutoSizeDrawableEditText extends androidx.appcompat.widget.AppCompatEditText {
    //drawablestart 이미지의 높이를 무시하고 해당 Edittext 뷰의 텍스트 높이와 패딩값만을 활용하여 높이를 계산처리해서 보여주는 뷰이며 너비는 무조건 부모뷰의 너비 match_parent 값으로 가져오게 처리했습니다.

    public AutoSizeDrawableEditText(Context context) {
        super(context);
    }

    public AutoSizeDrawableEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AutoSizeDrawableEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //drawablestart 이미지의 높이를 무시하고 해당 텍스트뷰의 텍스트 높이와 패딩값만을 활용하여 높이를 계산처리 로직

        // 상위 클래스(즉 원래의 edittext 측정방식)의 측정을 주석처리 합니다.
        // 지금 이 뷰는 너비는 무조건 match_parent 이고 높이는 이 뷰의 텍스트 높이 + 패딩값 이기 때문에 super.onMeasure()를 사용하지 않았습니다.
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
        
        // 부모로부터 제공된 너비 크기입니다, 즉 match_parent를 통해 측정된 부모뷰의 너비 값을 가져옵니다.
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        Paint.FontMetrics fontMetrics = getPaint().getFontMetrics();
        // 절대값을 사용하여 텍스트 영역 높이를 계산합니다.
        float textHeight = Math.abs(fontMetrics.top) + Math.abs(fontMetrics.bottom); 
        // 패딩을 포함한 최종 높이를 계산합니다.
        int desiredHeight = (int) (textHeight + getPaddingTop() + getPaddingBottom()); 

        // 최종 측정된 너비와 높이를 설정합니다. 너비는 상위 레이아웃의 측정 결과를 사용하고, 높이는 계산된 값을 사용합니다.
        setMeasuredDimension(widthSize, desiredHeight);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 뷰의 높이가 결정된 후 drawableStart의 크기를 조절합니다.
        // => 위의 onMeasure()를 활용하여 텍스트와 패딩값을 기준으로한 높이를 결정, 상위 레이아웃의 너비로 결정 한 뒤에 아래의 adjustDrawableSize()를 활용하여 이미지 사이즈를 텍스트 영역의 높이에 맞춰 설정합니다
        adjustDrawableSize();
    }

    private void adjustDrawableSize() {
        Drawable[] drawables = getCompoundDrawables();
        // drawableStart가 있는지 확인하는 절차입니다.
        if (drawables[0] != null) {
        
            Paint.FontMetrics fontMetrics = getPaint().getFontMetrics();
            // 절대값을 사용하여 텍스트 영역 높이를 계산합니다
            float textHeight = Math.abs(fontMetrics.top) + Math.abs(fontMetrics.bottom);

            Drawable drawableStart = drawables[0];
            float intrinsicWidth = drawableStart.getIntrinsicWidth();
            float intrinsicHeight = drawableStart.getIntrinsicHeight();
            // 텍스트 영역 높이 기준으로 비율을 계산합니다 => 텍스트 영역 높이에 비교하여 이미지 실제 높이는 몇분의 몇으로 할지 설정
            float scaleFactor = textHeight / intrinsicHeight;
            
            // (텍스트 높이에 맞게 설정한 비율)에 맞게 너비값 계산합니다, int값 변환
            int drawableWidth = (int) (intrinsicWidth * scaleFactor);
            // 텍스트 높이 값을 int값으로 변환합니다.
            int drawableHeight = (int) textHeight;

            //위의 너비, 높이 값을 활용해 이미지를 설정해줍니다.
            drawableStart.setBounds(0, 0, drawableWidth, drawableHeight);
            setCompoundDrawables(drawableStart, drawables[1], drawables[2], drawables[3]);
        }
    }
}

=> 너비는 상위 레이아웃의 너비를 가져오고 높이는 텍스트의 글자 높이에 맞춰 계산 처리되도록 간단히 만들었습니다.

 

흐름을 간단히 말씀드리겠습니다..

1. onMeasure()에서 텍스트의 높이 와 패딩값에 맞춰 뷰의 높이를 결정합니다.

2. onSizeChanged() 에서 1에 의해 측정된 높이에 맞춰 이미지의 사이즈를 설정합니다.

 

 

실행결과

 

=>뷰의 textSize 속성에 맞춰 크기가 자동 조절된 drawableStart 이미지가 보이게  됩니다. 만약 textSize를 sp로 설정했다면 기기의 글자 크기 조절 설정 따라 이미지 역시 크기가 변화합니다.