Android Studio中EditText自动调整文本大小失效及自定义行间距问题求助
Hey there! Let's break down solutions for both of your desired effects, since you've already tried common approaches and hit specific roadblocks:
1. Auto-adjust text size to fit EditText width per added element
The native autoSizeTextType you tried works to fit the entire text content within the EditText's height, not to shrink text so each manually added line (your "element") fits the width without wrapping. To fix this, we'll create a custom AutoFitEditText that adjusts the font size based on the longest line in your text.
Step-by-Step Implementation
a. Create the custom EditText class
public class AutoFitEditText extends AppCompatEditText { private float minTextSize; private float maxTextSize; private float stepGranularity; private final Paint textPaint = new Paint(); public AutoFitEditText(Context context) { super(context); initDefaults(); } public AutoFitEditText(Context context, AttributeSet attrs) { super(context, attrs); // Load custom attributes from XML TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.AutoFitEditText); minTextSize = ta.getDimension(R.styleable.AutoFitEditText_minTextSize, spToPx(8)); maxTextSize = ta.getDimension(R.styleable.AutoFitEditText_maxTextSize, spToPx(28)); stepGranularity = ta.getDimension(R.styleable.AutoFitEditText_stepGranularity, spToPx(1)); ta.recycle(); initDefaults(); } private void initDefaults() { textPaint.set(getPaint()); setTextSize(TypedValue.COMPLEX_UNIT_PX, maxTextSize); // Listen for text changes to adjust size addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { adjustTextSize(); } @Override public void afterTextChanged(Editable s) {} }); } private void adjustTextSize() { if (getText().length() == 0 || getWidth() == 0) return; int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight(); float currentSize = maxTextSize; String[] lines = getText().toString().split("\n"); float maxLineWidth = 0; // Calculate width of longest line at current size textPaint.setTextSize(currentSize); for (String line : lines) { float lineWidth = textPaint.measureText(line); if (lineWidth > maxLineWidth) maxLineWidth = lineWidth; } // Shrink size until longest line fits or we hit min size while (maxLineWidth > availableWidth && currentSize > minTextSize) { currentSize -= stepGranularity; textPaint.setTextSize(currentSize); maxLineWidth = 0; for (String line : lines) { float lineWidth = textPaint.measureText(line); if (lineWidth > maxLineWidth) maxLineWidth = lineWidth; } } setTextSize(TypedValue.COMPLEX_UNIT_PX, currentSize); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // Re-adjust if width changes (e.g., screen rotation) if (w != oldw) adjustTextSize(); } private float spToPx(float sp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics()); } }
b. Add custom attributes to res/values/attrs.xml
<declare-styleable name="AutoFitEditText"> <attr name="minTextSize" format="dimension" /> <attr name="maxTextSize" format="dimension" /> <attr name="stepGranularity" format="dimension" /> </declare-styleable>
c. Use the custom EditText in your layout
<com.yourpackage.AutoFitEditText android:id="@+id/exercise" android:layout_width="300dp" <!-- Your fixed width --> android:layout_height="wrap_content" android:inputType="textMultiLine|textCapSentences" app:minTextSize="8sp" app:maxTextSize="28sp" app:stepGranularity="1sp" />
Now, every time you add an element to the EditText, the font size will automatically shrink to fit the longest line within the EditText's width.
2. Add spacing between manually added elements (not auto-wrapped lines)
The lineSpacingExtra attribute applies to all lines, including auto-wrapped ones. Instead, we'll use Spannable Strings to add spacing only between your manually added elements (each separated by \n).
Implementation
When adding a new element to the EditText, wrap it in a Spannable to add a top margin to the new element (skip this for the first element):
EditText exercise = findViewById(R.id.exercise); String newElement = "Your long text that may wrap automatically"; SpannableStringBuilder ssb = new SpannableStringBuilder(exercise.getText()); // Add spacing if this isn't the first element if (exercise.getText().length() > 0) { ssb.append("\n"); // Convert desired dp spacing to pixels int paragraphSpacing = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 16, // Adjust this value for your desired spacing getResources().getDisplayMetrics() ); // Add a margin to the start of the new element ssb.setSpan( new LeadingMarginSpan.Standard(0, paragraphSpacing), ssb.length(), ssb.length() + newElement.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE ); } // Append the new element ssb.append(newElement); exercise.setText(ssb);
How it works:
LeadingMarginSpan.Standard(0, paragraphSpacing)adds extra space above the new element's first line.- Auto-wrapped lines within the same element will only use the EditText's default line spacing (set with
android:lineSpacingExtraif needed). - You can adjust the
16value to control how much spacing appears between your elements.
内容的提问来源于stack exchange,提问作者Malte Ge

