Text wrap around image in fragments - java

Im trying to set wrap text around image in one of my Fragments but it isn't working. Can somebody help me to solve this issue?
code in xml Fragment4
<RelativeLayout 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="make.appaplication.Fragment4">
<!-- TODO: Update blank fragment layout -->
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:src="#drawable/nature"
android:id="#+id/imageView"
android:layout_weight="1"
android:layout_marginRight="17dp"
android:layout_marginEnd="17dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<TextView
android:id="#+id/textView3"
android:textSize="17dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/text_page_1"
android:layout_below="#+id/textView5"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
code in class MyLeadingMarginSpan2
public class MyLeadingMarginSpan2 implements LeadingMarginSpan.LeadingMarginSpan2 {
private int margin;
private int lines;
private boolean wasDrawCalled = false;
private int drawLineCount = 0;
public MyLeadingMarginSpan2(int lines, int margin) {
this.margin = margin;
this.lines = lines;
}
#Override
public int getLeadingMargin(boolean first) {
boolean isFirstMargin = first;
// a different algorithm for api 21+
if (Build.VERSION.SDK_INT >= 21) {
this.drawLineCount = this.wasDrawCalled ? this.drawLineCount + 1 : 0;
this.wasDrawCalled = false;
isFirstMargin = this.drawLineCount <= this.lines;
}
return isFirstMargin ? this.margin : 0;
}
#Override
public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
this.wasDrawCalled = true;
}
#Override
public int getLeadingMarginLineCount()
{
return this.lines;
}
}
and code in class Fragment4
String text = getString(R.string.text_page_1);
SpannableString ss = new SpannableString(text);
Drawable dIcon = ContextCompat.getDrawable(getActivity(),R.drawable.nature);
int rightMargin = dIcon.getIntrinsicWidth() + 10;
ss.setSpan(new MyLeadingMarginSpan2(3, rightMargin), 0, ss.length(), 0);
final TextView messageView = (TextView) view.findViewById(R.id.textView3);
messageView.setText(ss);
Here is what I have now

Related

Nested Constraint layouts and huge layout inflation times

I have a lot of layouts like below. Also the same with NestedScrollView instead of the CardView.
But in all cases this leads to nested constraint layouts. Particuallary in one screen I use the following a lot as a custom view type. But this leads to HUGE inflation times. I meassured 500 ms and more. This is of course unaccaptable.
What can I do to improve the layout performance. The custom view is an EditText that looks like
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView
android:id="#+id/cardView"
android:layout_width="0dp"
android:layout_height="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--Some layout code -->
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toStartOf="parent"
app:layout_constraintStart_toStartOf="#+id/cardView"
app:layout_constraintTop_toBottomOf="#+id/cardView" />
</androidx.constraintlayout.widget.ConstraintLayout>
EDIT: As per request. Here comes the complete xml, java, and how I use it in another xml
CustomEditText.xml:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingStart="8dp"
android:paddingTop="9dp"
android:paddingEnd="8dp">
<com.google.android.material.card.MaterialCardView
android:id="#+id/cardView"
android:layout_width="0dp"
android:layout_height="48dp"
app:cardCornerRadius="12dp"
app:cardElevation="3dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_goneMarginBottom="10dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/iv_startIcon"
android:layout_width="19dp"
android:layout_height="0dp"
android:layout_marginStart="19dp"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp"
android:adjustViewBounds="true"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="?attr/colorPrimary"
tools:srcCompat="#drawable/icon_phone"
tools:visibility="visible" />
<TextView
android:id="#+id/tv_prefix_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="19dp"
android:textColor="?attr/colorPrimary"
android:visibility="gone"
android:textSize="13sp"
tools:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="ABC" />
<androidx.constraintlayout.widget.Barrier
android:id="#+id/barrier_start"
android:layout_width="1dp"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="tv_prefix_text,iv_startIcon" />
<androidx.appcompat.widget.AppCompatEditText
android:id="#+id/et_text"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="13dp"
android:layout_marginEnd="19dp"
android:background="#null"
android:textSize="13sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/barrier_end"
app:layout_constraintStart_toEndOf="#+id/barrier_start"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="#+id/tv_hint"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="13dp"
android:gravity="center_vertical"
android:textSize="13sp"
android:maxLines="1"
android:layout_marginEnd="57dp"
android:ellipsize="end"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/barrier_start"
app:layout_constraintTop_toTopOf="parent"
tools:hint="Hint text" />
<androidx.constraintlayout.widget.Barrier
android:id="#+id/barrier_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="left"
app:constraint_referenced_ids="iv_endIcon,tv_optional" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_optional"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginEnd="19dp"
android:alpha="0.44"
android:gravity="center_vertical"
android:text="#string/edit_text_optional"
android:textSize="10sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/iv_endIcon"
android:layout_width="39dp"
android:layout_height="0dp"
android:layout_marginEnd="9dp"
android:adjustViewBounds="true"
android:paddingStart="10dp"
android:paddingTop="18dp"
android:paddingEnd="10dp"
android:paddingBottom="18dp"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="#+id/barrier_end"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="#drawable/icon_alert"
tools:tint="?colorError"
tools:visibility="visible" />
<androidx.core.widget.ContentLoadingProgressBar
android:id="#+id/pb_loading"
style="?android:attr/progressBarStyle"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="7dp"
android:layout_marginEnd="14dp"
android:alpha="0.44"
android:textSize="9sp"
android:textStyle="bold"
android:fontFamily="#font/nunito2"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="#+id/cardView"
app:layout_constraintTop_toBottomOf="#+id/cardView"
tools:text="0/30"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tv_helper"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginTop="7dp"
android:layout_marginEnd="16dp"
android:alpha="0.44"
android:textSize="9sp"
android:visibility="visible"
app:layout_constraintEnd_toStartOf="#+id/tv_count"
app:layout_constraintStart_toStartOf="#+id/cardView"
app:layout_constraintTop_toBottomOf="#+id/cardView"
app:layout_goneMarginEnd="19dp"
tools:text="Helper text"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
and the CustomEditText.java (Sorry, this is a lot of code. But as I do not know what is important I could not reduce):
public class CustomEditText extends LinearLayoutCompat {
private static final String TAG = "CustomEditText";
private static final String ANDROID_NS = "http://schemas.android.com/apk/res/android";
private static final String APP_NS = "http://schemas.android.com/apk/res-auto";
private static final String COUNTER_SEPARATOR = "/";
private static final int TRANSLATION_Y_DP = 21;
private final int translationY;
private static final float HELPER_ALPHA = 0.44f;
private final String counterErrorText;
private final List<TextWatcher> textWatcherList = new ArrayList<>();
private final Drawable alertIcon;
private final Drawable clearIcon;
private final CustomEditTextBinding b;
private String errorText;
private String helperText;
private String hintText;
private Drawable startIcon;
private int iconTint;
private int counterMaxLength;
private boolean isCounterEnabled;
private boolean isOptional;
private boolean isProgressBarVisible = false;
private boolean isClearEnabled;
private boolean hasFocus;
private boolean isError = false;
private boolean isCounterError = false;
private String prefixText;
private final boolean initialized;
private final boolean hasBorder;
public CustomEditText(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
b = CustomEditTextBinding.inflate(LayoutInflater.from(context), this, true);
b.tvHint.setPivotX(0);
b.pbLoading.hide();
translationY = GuiUtils.dpToPx(context, TRANSLATION_Y_DP);
alertIcon = AppCompatResources.getDrawable(context, R.drawable.icon_alert);
clearIcon = AppCompatResources.getDrawable(context, R.drawable.icon_clear);
counterErrorText = context.getString(R.string.counter_max_length_error);
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CustomEditText);
//Start icon
startIcon = attributes.getDrawable(R.styleable.CustomEditText_startIcon);
iconTint = attributes.getColor(R.styleable.CustomEditText_iconTint, ColorUtils.getAttrColor(context, R.attr.colorPrimary));
refreshStartIcon();
//Hint text
hintText = attributes.getString(R.styleable.CustomEditText_hint);
refreshHintText();
//Helper text
helperText = attributes.getString(R.styleable.CustomEditText_helperText);
refreshHelperText();
//Error text
errorText = attributes.getString(R.styleable.CustomEditText_errorText);
//Prefix text
prefixText = attributes.getString(R.styleable.CustomEditText_prefixText);
refreshPrefixText();
isClearEnabled = attributes.getBoolean(R.styleable.CustomEditText_clearEnabled, false);
refreshClearEnabled();
//Optional text
isOptional = attributes.getBoolean(R.styleable.CustomEditText_optional, false);
refreshOptional();
b.ivEndIcon.setVisibility(GONE);
refreshEndIcon();
//Counter
isCounterEnabled = attributes.getBoolean(R.styleable.CustomEditText_counterEnabled, false);
counterMaxLength = attributes.getInt(R.styleable.CustomEditText_counterMaxLength, 0);
refreshCounter();
//Elevation
int elevation = attributes.getDimensionPixelSize(R.styleable.CustomEditText_elevation, -1);
if (elevation != -1) b.cardView.setCardElevation(elevation);
//Border
hasBorder = attributes.getBoolean(R.styleable.CustomEditText_hasBorder, false);
refreshStroke();
if (attrs != null) {
//Pass through to edit text
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importantForAutofill = attrs.getAttributeIntValue(ANDROID_NS, "importantForAutofill", 0);
b.etText.setImportantForAutofill(importantForAutofill);
String autofillHints = attrs.getAttributeValue(ANDROID_NS, "autofillHints");
b.etText.setAutofillHints(autofillHints);
}
//Focusable
boolean isFocusable = attrs.getAttributeBooleanValue(ANDROID_NS, "focusable", true);
b.etText.setFocusable(isFocusable);
//CursorVisible
boolean isCursorVisible = attrs.getAttributeBooleanValue(ANDROID_NS, "cursorVisible", true);
b.etText.setCursorVisible(isCursorVisible);
//InputType
int inputType = attrs.getAttributeIntValue(ANDROID_NS, "inputType", InputType.TYPE_CLASS_TEXT);
b.etText.setInputType(inputType);
//ImeOption
int imeOptions = attrs.getAttributeIntValue(ANDROID_NS, "imeOptions", EditorInfo.IME_ACTION_UNSPECIFIED);
b.etText.setImeOptions(imeOptions);
//MaxLines
int maxLines = attrs.getAttributeIntValue(ANDROID_NS, "maxLines", 1);
b.etText.setMaxLines(maxLines);
}
attributes.recycle();
initListeners();
initialized = true;
}
private void refreshClearEnabled() {
refreshEndIcon();
}
private void refreshOptional() {
if (isProgressBarVisible || !isOptional || isError || isCounterError || !isEmpty() && isClearEnabled)
b.tvOptional.setVisibility(GONE);
else b.tvOptional.setVisibility(VISIBLE);
}
private void refreshStartIcon() {
if (startIcon != null) {
b.ivStartIcon.setImageDrawable(startIcon);
b.ivStartIcon.setVisibility(VISIBLE);
b.tvPrefixText.setVisibility(GONE);
b.ivStartIcon.setImageTintList(ColorStateList.valueOf(iconTint));
} else {
b.ivStartIcon.setVisibility(GONE);
}
}
private void refreshPrefixText() {
if (prefixText != null) {
b.ivStartIcon.setVisibility(GONE);
b.tvPrefixText.setVisibility(VISIBLE);
b.tvPrefixText.setText(prefixText);
} else {
b.tvPrefixText.setVisibility(GONE);
}
}
private void refreshEndIcon() {
if (!isProgressBarVisible && (isError || isCounterError)) {
b.ivEndIcon.setVisibility(VISIBLE);
b.ivEndIcon.setImageDrawable(alertIcon);
b.ivEndIcon.setImageTintList(ColorUtils.getAttrColorList(getContext(), R.attr.colorError));
b.ivEndIcon.setAlpha(1f);
} else if (!isProgressBarVisible && isClearEnabled && !isEmpty()) {
b.ivEndIcon.setImageDrawable(clearIcon);
b.ivEndIcon.setImageTintList(ColorUtils.getAttrColorList(getContext(), R.attr.colorOnBackground));
b.ivEndIcon.setVisibility(VISIBLE);
b.ivEndIcon.setAlpha(0.42f);
} else {
b.ivEndIcon.setVisibility(GONE);
}
}
private void refreshHelperText() {
if (isError || isCounterError) {
if (isCounterError) b.tvHelper.setText(counterErrorText);
else b.tvHelper.setText(errorText);
b.tvHelper.setVisibility(VISIBLE);
b.tvHelper.setAlpha(1f);
b.tvHelper.setTextColor(ColorUtils.getAttrColor(getContext(), R.attr.colorError));
} else if (helperText == null) {
b.tvHelper.setVisibility(INVISIBLE);
} else {
b.tvHelper.setAlpha(HELPER_ALPHA);
b.tvHelper.setVisibility(VISIBLE);
b.tvHelper.setText(helperText);
b.tvHelper.setTextColor(ColorUtils.getAttrColor(getContext(), R.attr.colorOnBackground));
}
}
private void refreshCounter() {
if (isCounterEnabled) {
b.tvCount.setVisibility(VISIBLE);
refreshCounterText();
} else {
b.tvCount.setVisibility(GONE);
}
}
private void refreshStroke() {
if (isError || isCounterError) {
setStroke(StrokeType.ERROR);
} else if (hasFocus) {
setStroke(StrokeType.FOCUS);
} else if (hasBorder) {
setStroke(StrokeType.DEFAULT);
} else {
setStroke(StrokeType.NONE);
}
}
private void refreshProgressBar() {
refreshOptional();
refreshClearEnabled();
if (isProgressBarVisible) b.pbLoading.show();
else b.pbLoading.hide();
}
#SuppressLint("SetTextI18n")
private void refreshCounterText() {
if (!isCounterEnabled) return;
int countChars = getText().length();
String counterText = countChars + COUNTER_SEPARATOR + counterMaxLength;
isCounterError = countChars > counterMaxLength;
if(initialized && isCounterError) setError();
b.tvCount.setText(counterText);
}
private void refreshHintText() {
b.tvHint.setHint(hintText);
}
private void initListeners() {
b.etText.addTextChangedListener((TextWatcherAdapter) (s, start, before, count) -> {
//Do not trigger on init, only on user interaction
if (!initialized) return;
if (s.length() == 1) triggerAnimation(true);
else if (s.length() == 0) triggerAnimation(false);
});
b.etText.setOnFocusChangeListener((v, hasFocus) -> {
this.hasFocus = hasFocus;
refreshError();
refreshStroke();
});
b.etText.addTextChangedListener((TextWatcherAdapter) (s, start, before, count) -> {
clearError();
refreshCounterText();
refreshEndIcon();
refreshOptional();
//Trigger all other TextWatchers, add them here instead of the text itself to trigger all internal ones first
for (TextWatcher textWatcher : textWatcherList) textWatcher.onTextChanged(s,start,before,count);
});
b.etText.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) {
}
#Override
public void afterTextChanged(Editable s) {
//Trigger all other TextWatchers, add them here instead of the text itself to trigger all internal ones first
for (TextWatcher textWatcher : textWatcherList) textWatcher.afterTextChanged(s);
}
});
b.etText.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_DONE) {
b.etText.clearFocus();
}
return false;
});
b.ivEndIcon.setOnClickListener(v -> {
if (isClearEnabled) b.etText.setText(null);
});
}
private void triggerAnimation(boolean fadeOut) {
if (fadeOut) {
b.tvHint.animate().translationY(-translationY * 0.32f).scaleX(0.7f).scaleY(0.7f);
//This works but not with setText because getHeight return 0. The reason for that: i do not know
//b.tvHint.animate().translationY(-b.tvHint.getHeight() * 0.32f).scaleX(0.7f).scaleY(0.7f);
} else {
b.tvHint.animate().translationY(0).translationX(0).scaleX(1f).scaleY(1f);
}
}
public void setText(String text) {
b.etText.setText(text);
if (text != null && !text.isEmpty()) triggerAnimation(true);
}
private void refreshError() {
refreshOptional();
refreshEndIcon();
refreshHelperText();
refreshStroke();
}
#Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
b.etText.setEnabled(enabled);
if (enabled) {
PictureUtils.saturatePicture(b.ivStartIcon, 1);
PictureUtils.saturatePicture(b.ivEndIcon, 1);
b.tvPrefixText.setTextColor(ColorUtils.getPrimary(getContext()));
if (isError) setStroke(StrokeType.ERROR);
else if (hasFocus) setStroke(StrokeType.FOCUS);
else setStroke(StrokeType.DEFAULT);
b.cardView.setCardBackgroundColor(ColorUtils.getAttrColor(getContext(), R.attr.cardColorOnPrimary));
} else {
PictureUtils.saturatePicture(b.ivStartIcon, 0);
PictureUtils.saturatePicture(b.ivEndIcon, 0);
b.tvPrefixText.setTextColor(ColorUtils.getAttrColor(getContext(), R.attr.colorItemDisabled));
setStroke(StrokeType.DISABLED);
b.cardView.setCardBackgroundColor(ColorUtils.getAttrColor(getContext(), R.attr.colorDisabled));
}
}
public void setError() {
isError = true;
refreshError();
}
public void setError(String errorText) {
if (errorText == null) {
clearError();
} else {
isError = true;
this.errorText = errorText;
refreshError();
}
}
public void clearError() {
isError = false;
//Its up to the user to decide that this will not be an error! So reset no matter if more is entered
isCounterError = false;
refreshError();
}
public boolean isValid() {
if (isOptional) return !isError;
else return !getText().isEmpty() && !isError;
}
private void setStroke(StrokeType strokeType) {
switch (strokeType) {
case ERROR:
b.cardView.setStrokeColor(ColorUtils.getAttrColor(getContext(), R.attr.colorError));
b.cardView.setStrokeWidth(4);
break;
case FOCUS:
b.cardView.setStrokeColor(ColorUtils.getAttrColor(getContext(), R.attr.colorPrimary));
b.cardView.setStrokeWidth(4);
break;
case DEFAULT:
int color = ColorUtils.getAttrColor(getContext(), R.attr.colorOnBackground);
ColorDrawable cd = new ColorDrawable(color);
cd.setAlpha(54);
b.cardView.setStrokeColor(cd.getColor());
b.cardView.setStrokeWidth(2);
break;
case DISABLED:
b.cardView.setStrokeColor(ColorUtils.getAttrColor(getContext(), R.attr.colorItemDisabled));
b.cardView.setStrokeWidth(2);
break;
case NONE:
b.cardView.setStrokeColor(null);
b.cardView.setStrokeWidth(0);
break;
}
}
public String getText() {
return b.etText.getEditableText().toString().trim();
}
public void addTextChangedListener(TextWatcher textWatcher) {
//b.etText.addTextChangedListener(textWatcher);
textWatcherList.add(textWatcher);
}
public boolean isEmpty() {
return StringUtils.checkNull(getText());
}
#Override
public void setOnClickListener(#Nullable OnClickListener listener) {
b.etText.setOnClickListener(listener);
}
public void setErrorText(String errorText) {
this.errorText = errorText;
}
public void setHelperText(String helperText) {
this.helperText = helperText;
refreshHelperText();
}
public void setHintText(String hintText) {
this.hintText = hintText;
refreshHintText();
}
public void setStartIcon(Drawable startIcon) {
this.startIcon = startIcon;
refreshStartIcon();
}
public void setPrefixText(String prefix) {
this.prefixText = prefix;
refreshPrefixText();
}
public void setLoading(boolean active) {
this.isProgressBarVisible = active;
refreshProgressBar();
}
public void setCounterMaxLength(int counterMaxLength) {
this.counterMaxLength = counterMaxLength;
refreshCounter();
}
public void setCounterEnabled(boolean counterEnabled) {
isCounterEnabled = counterEnabled;
refreshCounter();
}
public void setOptional(boolean optional) {
isOptional = optional;
refreshOptional();
}
public void setClearEnabled(boolean clearEnabled) {
isClearEnabled = clearEnabled;
refreshClearEnabled();
}
public boolean isCounterError() {
return isCounterError;
}
#Override
public void setFocusable(boolean focusable) {
b.etText.setFocusable(focusable);
}
public void setCursorVisible(boolean cursorVisible) {
b.etText.setCursorVisible(cursorVisible);
}
public boolean isError() {
return isError || isCounterError;
}
private enum StrokeType {ERROR, FOCUS, DEFAULT, DISABLED, NONE}
// TODO: 13.10.2021 Text drawable needs to get bigger
public void scalePictureForText() {
LayoutParams params = new LayoutParams(30, 0);
params.setMargins(19, 5, 0, 5);
b.ivStartIcon.setLayoutParams(params);
}
}
And this is how I use it in another layout (I removed the constraints):
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:fillViewport="true"
android:overScrollMode="never">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal">
<com.company.app.views.CustomEditText
android:id="#+id/et_number_primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:imeOptions="actionDone"
android:inputType="numberDecimal"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<!--Button that should not scroll-->
</androidx.constraintlayout.widget.ConstraintLayout>
I would suggest using ViewStubs for all of the optional parts of the layout, that is items with gone visibility by default. Then these parts won't be inflated until they become visible or are needed, which should save you some initial inflation time.
And maybe you could eliminate the MaterialCardView and then combine the constraint layouts once there's no MaterialCardView between them, less layouts means less inflation time. It looks like you're using MaterialCardView for curved corners and shadows, but you could try to make your own background with curved corners and shadows and then apply it directly to the constraint layout to get the same effect with less layouts.
Is there any reason why your custom view extends LinearLayoutCompat? Could make it a constraint layout and use merge as a root tag to eliminate one layout.
Also, you have a huge amount of code in your constructor which might be the biggest culprit, could you try putting timers in your constructor and logging how much time it takes for b = CustomEditTextBinding.inflate(LayoutInflater.from(context), this, true); vs how much time it takes for everything else in there to complete. That will tell you if the problem is really layout related or if you're doing too many things in the constructor.
I can suggest you some methods to analyze your layout :
You can use Lint tool . Select Analyze (from the top bar) -> Inspect code -> select your layout file or the whole project if you want. this will automatically detect problems in your layout and will suggests fixes for it.
You can also use Profile GPU rendering in the developers option in your device. This tool allows you to see how long the layout-and-measurestage is taking for each frame of rendering. This data can help you diagnose runtime performance issues, and help you determine what, if any layout-and-measure issues you need to address.
Or enable Debug GPU Overdraw option from the developer options to show which area of your ui is overdrawn.
For your help : Inspect GPU rendering speed and overdraw
ConstraintLayout was added to flatten the view hierarchies and is not a light View to inflate. They are not design to be nested, so I would suggest you not to use them if you can avoid using them. In most cases FrameLayout or LinearLayout is sufficient.

Error: android.widget.LinearLayout cannot be cast to android.widget.ImageView

There was already someone else with a similar problem, but I couldn't understand the anwser and I wasn't able to add a coment to receive
more informations. So please help me!
This is my main JavaClass
package ch.androidnewcomer.muckenfangfinal;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Date;
import java.util.Random;
public class GameActivity extends Activity implements View.OnClickListener, Runnable{
public static final int DELAY_MILLIS = 1000;
public static final int ZEITSCHEIBEN = 60;
public float massstab;
private int runde;
private int punkte;
private int muecken;
private int gefangeneMuecken;
private int zeit;
private static final long HOECHSTALTER_MS = 2000;
private Random zufallsgenerator = new Random();
private ViewGroup spielbereich;
private Handler handler = new Handler();
private boolean spielLaeuft;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
massstab = getResources().getDisplayMetrics().density;
spielbereich = (ViewGroup)findViewById(R.id.spielbereich);
spielStarten();
}
private void spielStarten() {
spielLaeuft = true;
runde = 0;
punkte = 0;
starteRunde();
}
private void bildschirmAktualisieren() {
TextView tvPunkte = (TextView)findViewById(R.id.points);
tvPunkte.setText(Integer.toString(punkte));
TextView tvRunde = (TextView)findViewById(R.id.round);
tvRunde.setText(Integer.toString(runde));
TextView tvTreffer = (TextView)findViewById(R.id.hits);
tvTreffer.setText(Integer.toString(gefangeneMuecken));
TextView tvZeit = (TextView)findViewById(R.id.time);
tvZeit.setText(Integer.toString(zeit/(1000/DELAY_MILLIS)));
FrameLayout flTreffer = (FrameLayout)findViewById(R.id.bar_hits);
FrameLayout flZeit = (FrameLayout)findViewById(R.id.bar_time);
ViewGroup.LayoutParams lpTreffer = flTreffer.getLayoutParams();
lpTreffer.width = Math.round( massstab * 300 * Math.min( gefangeneMuecken,muecken) / muecken);
ViewGroup.LayoutParams lpZeit = flZeit.getLayoutParams();
lpZeit.width = Math.round( massstab * zeit *300 / ZEITSCHEIBEN);
}
private void zeitHerunterzaehlen() {
zeit = zeit - 1;
if(zeit % (1000/DELAY_MILLIS) == 0) {
float zufallszahl = zufallsgenerator.nextFloat();
double wahrscheinlichkeit = muecken * 1.5;
if (wahrscheinlichkeit > 1) {
eineMueckeAnzeigen();
if (zufallszahl < wahrscheinlichkeit - 1) {
eineMueckeAnzeigen();
}
} else {
if (zufallszahl < wahrscheinlichkeit) {
eineMueckeAnzeigen();
}
}
}
mueckenVerschwinden();
bildschirmAktualisieren();
if(!pruefeSpielende()) {
if(!pruefeRundenende()) {
handler.postDelayed(this, DELAY_MILLIS);
}
}
}
private boolean pruefeRundenende() {
if (gefangeneMuecken >= muecken) {
starteRunde();
return true;
}
return false;
}
private void starteRunde() {
runde = runde +1;
muecken = runde *10;
gefangeneMuecken = 0;
zeit = ZEITSCHEIBEN;
bildschirmAktualisieren();
handler.postDelayed(this, DELAY_MILLIS);
}
private boolean pruefeSpielende() {
if(zeit == 0 && gefangeneMuecken < muecken) {
gameOver();
return true;
}
return false;
}
private void gameOver() {
Dialog dialog = new Dialog(this, android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
dialog.setContentView(R.layout.gameover);
dialog.show();
spielLaeuft = false;
}
private void mueckenVerschwinden() {
int nummer=0;
while (nummer < spielbereich.getChildCount()) {
ImageView muecke = (ImageView)spielbereich.getChildAt(nummer);
Date geburtsdatum = (Date) muecke.getTag(R.id.geburtsdatum);
long alter = (new Date()).getTime() - geburtsdatum.getTime();
if(alter > HOECHSTALTER_MS) {
spielbereich.removeView(muecke);
}else {
nummer++;
}
}
}
private void eineMueckeAnzeigen() {
int breite = spielbereich.getWidth();
int hoehe = spielbereich.getHeight();
int muecke_breite = (int) Math.round(massstab* 60);
int muecke_hoehe = (int) Math.round(massstab*49);
int links = zufallsgenerator.nextInt(breite - muecke_breite);
int oben = zufallsgenerator.nextInt(hoehe - muecke_hoehe);
ImageView muecke = new ImageView(this);
muecke.setImageResource(R.drawable.muecke);
muecke.setOnClickListener(this);
muecke.setTag(R.id.geburtsdatum, new Date());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(muecke_breite, muecke_hoehe);
params.leftMargin = links;
params.topMargin = oben;
params.gravity = Gravity.TOP + Gravity.LEFT;
spielbereich.addView(muecke,params);
}
#Override
public void onClick(View muecke) {
gefangeneMuecken++;
punkte += 100;
bildschirmAktualisieren();
spielbereich.removeView(muecke);
}
#Override
public void run() {
zeitHerunterzaehlen();
}
}
The FrameLayout, where I'm trying to display the 'muecke - mosquito' is called 'spielbereich' meaning as much as playground.
And this is the LogCat
12-28 16:19:26.449 5302-5302/ch.androidnewcomer.muckenfangfinal E/AndroidRuntime: FATAL EXCEPTION: main
Process: ch.androidnewcomer.muckenfangfinal, PID: 5302
java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.widget.ImageView
at ch.androidnewcomer.muckenfangfinal.GameActivity.mueckenVerschwinden(GameActivity.java:168)
at ch.androidnewcomer.muckenfangfinal.GameActivity.zeitHerunterzaehlen(GameActivity.java:104)
at ch.androidnewcomer.muckenfangfinal.GameActivity.run(GameActivity.java:218)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
And here is my xmlLayout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="ch.androidnewcomer.muckenfangfinal.GameActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="61dp">
<TextView
android:id="#+id/round"
android:layout_width="136dp"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="21sp"
android:textStyle="bold" />
<TextView
android:id="#+id/points"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="TextView"
android:textSize="21sp"
android:textStyle="bold" />
</FrameLayout>
<FrameLayout
android:id="#+id/spielbereich"
android:layout_width="match_parent"
android:layout_height="332dp"
android:layout_weight="1">
<LinearLayout
android:id="#+id/hintergrundlinearlayout"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_gravity="bottom"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="35dp">
<FrameLayout
android:id="#+id/bar_hits"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:background="#android:color/holo_orange_dark">
</FrameLayout>
<TextView
android:id="#+id/hits"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="#string/hits"
android:textSize="15sp"
android:textStyle="bold" />
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/bar_time"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:background="#android:color/holo_orange_light">
</FrameLayout>
<TextView
android:id="#+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="#string/time" />
</FrameLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>
if you need anymore informations, please tell me.
It would be great if you could tell me exactely how I have to change the code, because I'm really a beginner.
you are casting a linear layout to imageview.You are trying to get a child of frame layout which is a linear layout but you casted it to a image view.thats why this error was happened. casting it to the linearlayout will solve this error.
This is your layout with id spielbereich
<FrameLayout
android:id="#+id/spielbereich"
android:layout_width="match_parent"
android:layout_height="332dp"
android:layout_weight="1">
<LinearLayout
android:id="#+id/hintergrundlinearlayout"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_gravity="bottom"
android:orientation="vertical">
And this is the code where you are trying to cast the childView into an ImageView
private void mueckenVerschwinden() {
int nummer=0;
while (nummer < spielbereich.getChildCount()) {
ImageView muecke = (ImageView)spielbereich.getChildAt(nummer);
Date geburtsdatum = (Date) muecke.getTag(R.id.geburtsdatum);
long alter = (new Date()).getTime() - geburtsdatum.getTime();
if(alter > HOECHSTALTER_MS) {
spielbereich.removeView(muecke);
}else {
nummer++;
}
}
}
ImageView muecke = (ImageView)spielbereich.getChildAt(nummer);
This line is giving you a cast error because nummer = 0 at this point and spielbereich.getChildAt(0) is a LinearLayout

TextView breaks my word by letters

My requirements: create "incoming bubble" with width by content and max width 90%.
I have this markup:
<?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="wrap_content"
android:orientation="horizontal"
android:weightSum="1.0"
tools:background="#color/white_smoke">
<LinearLayout
android:id="#+id/flBubble"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:background="#drawable/bubble_in"
android:layout_weight="0.9">
<ImageView
android:id="#+id/ivSay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="#string/default_content_description"
android:padding="8dp"
android:src="#drawable/ic_play_circle_outline_black_24dp"
android:tint="#color/primary"/>
<TextView
android:id="#+id/tvValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="8dp"
android:textColor="#color/black"
android:textSize="16sp"
tools:text="I would like to go to an Italian restaurant"/>
</LinearLayout>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0.1"/>
</LinearLayout>
Sometimes I get the following result:
But I expect the following result (it's falsely encouraging screenshot from Android Studio preview):
How can I prevent breaking word restaraunt by letters?
UPDATE
Although I use minSdk=15 I tried to use breakStrategy and I haven't get expected result.
android:breakStrategy="simple":
android:breakStrategy="balanced":
I found a related question: Force next word to a new line if the word is too long for the textview, but I didn't undestand how can I get maximum available width for TextView with layout_width="wrap_content?
It would be great if I could override the TextView.setText and place line breaks there if needed.
OMG, there were in my string!
value.replaceAll("\\s", " ");
Thank you all!
Use MaxWidth property for textview or else you should provide width for textview
<com.custom.views.CustomTextView
android:id="#+id/txt_send_chat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:maxWidth="250dp"
android:textColor="#color/color_chat_sender"
android:textSize="16sp"
app:font_name="#string/font_roboto_regular" />
You can use webview to achieve this behavior.
In webview you can use css to adjust text.
Take a look at this answer
Update
You can calculate width of string and add \n to string where is string needs to split
Rect bounds = new Rect();
Paint textPaint = textView.getPaint();
textPaint.getTextBounds(text, 0, text.length(), bounds);
int height = bounds.height();
int width = bounds.width();
Results is in pixels, so just check width of your view or screen and split the string.
UPDAE2: Example Code
I just wrote an example with simple layout in activity onCreate you can implement it in adapter or whatever works for you.
TextView textView = (TextView) findViewById(R.id.txt); //textview with empty text
Rect bounds = new Rect();
Paint textPaint = textView.getPaint();
String text = "some long text here.....";// text data to work on
textPaint.getTextBounds(text, 0, text.length(), bounds);
int textWidth = bounds.width();// get text width in pixel
int marginPadding = 100;// we have some padding and margin from xml layouts
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int rootWidth = displayMetrics.widthPixels-marginPadding;// maximum width on screan
if (textWidth > rootWidth) { // check if need to split the string.
int lineMax = (text.length() * rootWidth) / textWidth; // maximum Characters for each line
String result = text.replaceAll("(.{" + String.valueOf(lineMax) + "})", "$1\n"); // regex to replace each group(lineMax) of Chars with group of char + new line
textView.setText(result);
} else
textView.setText(text);
UPDATE#3: Fixed code for Listview
onCreate
ArrayList<String> data = new ArrayList<>();
data.add("000");
data.add("aaaaaaaaaaa");
data.add("aaaaaaaaaaa bbbbbbbbbbbb");
data.add("aaaaaaaaaaa bbbbbbbbbbbb cccccccccccccccc");
data.add("aaaaaaaaaaa bbbbbbbbbbbb cccccccccccccccc ddddddddddddd");
data.add("aaaaaaaaaaa bbbbbbbbbbbb cccccccccccccccc ddddddddddddd eeeeeeeeeeeee");
data.add("aaaaaaaaaaa bbbbbbbbbbbb cccccccccccccccc ddddddddddddd eeeeeeeeeeeee ffffffffffffffffff");
data.add("aaaaaaaaaaa bbbbbbbbbbbb cccccccccccccccc ddddddddddddd eeeeeeeeeeeee ffffffffffffffffff gggggggggggggggg");
data.add("aaaaaaaaaaa bbbbbbbbbbbb cccccccccccccccc ddddddddddddd eeeeeeeeeeeee ffffffffffffffffff gggggggggggggggg hhhhhhhhhhhhhhhh");
ListView listView = (ListView) findViewById(R.id.listview);
MyAdapter adapter= new MyAdapter(data,this);
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();
MyAdapter.java
public class MyAdapter extends BaseAdapter {
private LayoutInflater inflater = null;
Context context;
ArrayList<String> data;
public MyAdapter(ArrayList<String> data, Context context) {
this.context = context;
this.data = data;
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int i) {
return data.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(final int i, View convertView, ViewGroup viewGroup) {
final View view = inflater.inflate(R.layout.item, null);
final TextView tv_text = (TextView) view.findViewById(R.id.tvValue);
if (data.get(i) != null) {
tv_text.post(new Runnable() {
#Override
public void run() {
//TextView is Ready to be used.
fixText(data.get(i),tv_text);
}
});
}
return view;
}
private void fixText(String text, TextView textView) {
Rect bounds = new Rect();
Paint textPaint = textView.getPaint();
textPaint.getTextBounds(text, 0, text.length(), bounds);
int textWidth = bounds.width();// get text width in pixel
int marginPadding = 100;// we have some padding and margin from xml layouts
DisplayMetrics displayMetrics = new DisplayMetrics();
((MainActivity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int rootWidth = textView.getWidth();//displayMetrics.widthPixels - marginPadding;// maximum width on screan
if (textWidth > rootWidth) { // check if need to split the string.
//int lineMax = (text.length() * rootWidth) / textWidth; // maximum Characters for each line
//String result = text.replaceAll("(.{" + String.valueOf(lineMax-5) + "})", "$1\n"); // regex to replace each group(lineMax) of Chars with group of char + new line
String result = wrapText(rootWidth,text);
textView.setText(result);
} else
textView.setText(text);
}
private String wrapText(int textviewWidth,String mQuestion) {
String temp = "";
String sentence = "";
String[] array = mQuestion.split(" "); // split by space
for (String word : array) {
if ((temp.length() + word.length()) < textviewWidth) { // create a temp variable and check if length with new word exceeds textview width.
temp += " "+word;
} else {
sentence += temp+"\n"; // add new line character
temp = word;
}
}
return (sentence.replaceFirst(" ", "")+temp);
}
item.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="wrap_content"
android:orientation="horizontal"
android:weightSum="1.0"
tools:background="#color/colorAccent">
<LinearLayout
android:id="#+id/flBubble"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:background="#color/colorPrimary"
android:layout_weight="0.9">
<ImageView
android:id="#+id/ivSay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="default_content_description"
android:padding="8dp"
android:src="#android:drawable/ic_media_play"
android:tint="#color/colorPrimaryDark" />
<TextView
android:id="#+id/tvValue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="8dp"
android:textColor="#000000"
android:textSize="16sp"
tools:text="I would like to go to an Italian restaurant jkjk l;'"/>
</LinearLayout>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0.1"/>
</LinearLayout>
Try this
<TextView
android:id="#+id/tvValue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="8dp"
android:textColor="#color/black"
android:textSize="16sp"
tools:text="I would like to go to an Italian restaurant"/>
</LinearLayout>
You can try with
Autosizing TextViews
The Support Library 26.0 provides full support to the autosizing TextView feature on devices running Android versions prior to Android 8.0 (API level 26). The library provides support to Android 4.0 (API level 14) and higher. The android.support.v4.widget package contains the TextViewCompat class to access features in a backward-compatible fashion
For Example:
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:autoSizeTextType="uniform" />
For more details Guidelines go HERE
Their is Library too HERE
Try this
private String getWidthFitString(String input) {
Paint paint = text.getPaint();
// you can define max width by your self
int maxWidth = getContentMaxWidth();
float width = paint.measureText(input);
if (width > maxWidth) {
List<String> words = Arrays.asList(input.split("\\s"));
int breakLinePosition = 0;
String toBreakLineText;
List<String> toBreakLineWords = new ArrayList<>();
while (breakLinePosition < words.size()) {
toBreakLineWords.add(words.get(breakLinePosition));
toBreakLineText = TextUtils.join(" ", toBreakLineWords);
float currentWidth = paint.measureText(toBreakLineText);
if (currentWidth > maxWidth) {
break;
}
breakLinePosition ++;
}
if (breakLinePosition > 1) {
toBreakLineWords.remove(toBreakLineWords.size() - 1);
toBreakLineText = TextUtils.join(" ", toBreakLineWords);
List<String> fromBreakLineWords = new ArrayList<>();
for (int i = breakLinePosition; i < words.size(); i++) {
fromBreakLineWords.add(words.get(i));
}
return toBreakLineText + "\n" + getWidthFitString(TextUtils.join(" ", fromBreakLineWords));
} else {
return input;
}
}
return input;
}
For those whose string has non-breaking space character may try the following:
value.replace("\u00A0", " ")
Hope this might help
Change your TextView to EditText and put this 2 lines. it should help you
android:inputType="textMultiLine"
android:enabled="false"
This will place you text properly and later on you can give a edit feature in your application if you need.

Adding EditText to a xml file not working

I have been working on an app and can't get EditText into an xml file.
I had it working, then I added a ScrollView and it didn't work at all so I deleted it and now it spreads out the groups throughout the screen, and I can't fix it.
PlayScreen.java
/**
* Created by Gavin on 8/10/2016.
*/
public class PlayScreen extends Activity {
public EditText numberOP;
private RelativeLayout layout;
private int i = 0;
private int x = 0;
private int y = 1;
private int z = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.layout_play);
numberOP = (EditText) findViewById(R.id.number_of_players);
layout = (RelativeLayout) findViewById(R.id.layout_play_id);
}
public void onEnterClickOne(View view) {
/**if(textView != null) {
layout.removeView(textView);
}
if(editText != null) {
layout.removeView(editText);
}*/
int b = 0;
if(i+y+x+z != 0) {
for (b = 0; b < i + y + x + z * 100; b++) {
System.out.println(b);
View v = findViewById(b);
if (v != null) {
layout.removeView(v);
}
}
}
i = 0;
x = 0;
y = 1;
z = 1;
if (numberOP.getText().toString().length() > 0) {
int length = Integer.parseInt(numberOP.getText().toString())*2;
for (i = 0; i < length; i++) {
if (i % 2 == 0) {
x++;
TextView textView = new TextView(PlayScreen.this);
textView.setId(x*30);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT));
textView.setText(String.format("Group: %s", Integer.toString(x)));
textView.setTextSize(20);
textView.setTypeface(null,Typeface.BOLD);
layout.addView(textView);
}
EditText editText = new EditText(PlayScreen.this);
editText.setId(i+1);
editText.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT));
if(y == 1) {
editText.setHint("Partner 1");
y++;
} else if(y == 2) {
editText.setHint("Partner 2");
y--;
}
layout.addView(editText);
}
}
}
}
layout_play.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
android:background="#f7f7f7"
android:id="#+id/layout_play_id"
android:padding="25dp">
<TextView
android:text="#string/choose_your_partners"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="31sp"
android:layout_centerHorizontal="true"
android:id="#+id/editTextTwo" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberSigned"
android:ems="10"
android:hint="#string/number_of_groups"
android:id="#+id/number_of_players"
android:layout_below="#+id/editTextTwo"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/button_1_text"
android:textSize="30sp"
android:id="#+id/playButton"
android:onClick="onEnterClickOne"
android:layout_below="#+id/number_of_players"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
Also, if you have any suggestions for ScrollView, that'd be awesome. Thanks.
The Problem
For such kind of view component, it is better to use LinearLayout with vertically orientation, to easily put the view component inside this.
RelativeLayout:
RelativeLayout enables you to specify how child views are positioned relative to each other. The position of each view can be specified as relative to sibling elements or relative to the parent.
LinearLayout:
LinearLayout is a view group that aligns all children in either vertically or horizontally.

Android: Get values of listview with multiple row layout

I have a listview with multiple row layouts (radio group, edit text, text view), with multiple choice mode. I want to retrieve it's selected data (user-selected or typed data) on a submit button.
This is the code from my main file:
public class GraduatingSurvey extends Fragment {
private static final String LOGTAG = "log" ;
public String stdcode = "024-15-16079";
Button submit;
RadioGroup radioGroup;
RadioButton radioButton;
EditText comment;
ArrayList<GraduatingSurveyModel> graduatingModelList;
ListView listView;
View view;
public GraduatingSurvey() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_graduating_survey, container, false);
submit = (Button) view.findViewById(R.id.btn_graduate_submit);
listView = (ListView) view.findViewById(R.id.graduate_list);
graduatingModelList = new ArrayList<GraduatingSurveyModel>();
//handle submit form Event.
submit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final int child=listView.getAdapter().getCount();
Log.i("radio", "child: " + child);
SparseBooleanArray checked = listView.getCheckedItemPositions(); //Is returning empty
Log.i("radio", "sparseArray: " + checked);
for(int i=0;i<child;i++) {
int type = listView.getAdapter().getItemViewType(i);
Log.i("radio", "type: " + type);
if(type == 2){
// Want to retrieve data here
}
if(type == 0)
{
}
if(type == 1){
}
}
}
});
NetAsync(view);
return view;
}
This is the adapter:
public class GraduatingSurveyAdapter extends ArrayAdapter<GraduatingSurveyModel> {
private static final int TYPE_ITEM1 = 0;
private static final int TYPE_ITEM2 = 1;
private static final int TYPE_ITEM3 = 2;
int type;
ArrayList<GraduatingSurveyModel> ArrayListSurvey;
int Resource;
Context context;
LayoutInflater vi;
public GraduatingSurveyAdapter(Context context, int resource, ArrayList<GraduatingSurveyModel> objects) {
super(context, resource, objects);
ArrayListSurvey = objects;
Resource = resource;
this.context = context;
vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getItemViewType(int position) {
if (position == 14){
type = TYPE_ITEM1;
} else if (position == 23 || position == 24 || position == 25){
type = TYPE_ITEM2;
}
else
{
type= TYPE_ITEM3 ;
}
return type;
}
#Override
public int getViewTypeCount() {
return 3;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
//first Item or row is being created hence ConvertView is NULL
if(convertView == null){
if (type == TYPE_ITEM2) {
convertView = vi.inflate(R.layout.graduates_survey_comment,null);
holder = new ViewHolder();
holder.tv_question = (TextView) convertView.findViewById(R.id.graduate_question);
holder.tv_comment = (TextView) convertView.findViewById(R.id.graduate_comment);
}
else if (type == TYPE_ITEM1) {
convertView = vi.inflate(R.layout.graduates_survey_subheader,null);
holder = new ViewHolder();
holder.tv_question = (TextView) convertView.findViewById(R.id.graduate_question);
}
else {
//infalte layout of normaltype
//Inflating items only once
convertView = vi.inflate(Resource,null);
holder = new ViewHolder();
holder.tv_question = (TextView) convertView.findViewById(R.id.graduate_question);
holder.tv_comment = (TextView) convertView.findViewById(R.id.graduate_comment);
holder.rg = (RadioGroup) convertView.findViewById(R.id.graduate_radioGroup);
holder.rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
/* RadioButton radioButton = (RadioButton) group.findViewById(checkedId);
Log.i("radio", "onCheckedChanged: " + radioButton + " " + checkedId);
notifyDataSetChanged();*/
Integer pos = (Integer) group.getTag();
GraduatingSurveyModel element = ArrayListSurvey.get(pos);
switch (checkedId) {
case R.id.graduate_sAgree:
element.current = GraduatingSurveyModel.ANSWER_ONE_SELECTED;
break;
case R.id.graduate_agree:
element.current = GraduatingSurveyModel.ANSWER_TWO_SELECTED;
break;
case R.id.graduate_uncertain:
element.current = GraduatingSurveyModel.ANSWER_THREE_SELECTED;
break;
case R.id.graduate_disagree:
element.current = GraduatingSurveyModel.ANSWER_FOUR_SELECTED;
break;
case R.id.graduate_sDisagree:
element.current = GraduatingSurveyModel.ANSWER_FIVE_SELECTED;
break;
default:
element.current = GraduatingSurveyModel.NONE; // Something was
}
}
});
}
convertView.setTag(holder);
}else{
//reuse code. (Inflate items only once then reuse them.)
holder = (ViewHolder) convertView.getTag();
}
// get info from ArrayList(that came through JSON), and set it in the View.
if (type == TYPE_ITEM1) {
holder.tv_question.setText(ArrayListSurvey.get(position).getQuestion());
}
else if (type == TYPE_ITEM2) {
holder.tv_question.setText(ArrayListSurvey.get(position).getQuestion());
}
else{
holder.rg.setTag(new Integer(position));
holder.tv_question.setText(ArrayListSurvey.get(position).getQuestion());
if(ArrayListSurvey.get(position).current != GraduatingSurveyModel.NONE){
RadioButton r = (RadioButton) holder.rg.getChildAt(ArrayListSurvey.get(position).current);
r.setChecked(true);
}else{
holder.rg.clearCheck();
}
}
return convertView;
}
static class ViewHolder{
private TextView tv_question;
private TextView tv_comment;
private LinearLayout lv_choices;
private RadioGroup rg;
}
}
This is my model:
public class GraduatingSurveyModel {
public String question;
public String comment;
public String choices;
public String subHeading;
public int current = NONE; // hold the answer picked by the user, initial is NONE(see below)
public static final int NONE = 1000; // No answer selected
public static final int ANSWER_ONE_SELECTED = 0; // first answer selected
public static final int ANSWER_TWO_SELECTED = 1; // second answer selected
public static final int ANSWER_THREE_SELECTED = 2; // third answer selected
public static final int ANSWER_FOUR_SELECTED = 3; // forth answer selected
public static final int ANSWER_FIVE_SELECTED = 4; // forth answer selected
public GraduatingSurveyModel() {
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public String getChoices() {
return choices;
}
public void setChoices(String choices) {
this.choices = choices;
}
public String getSubHeading() {
return subHeading;
}
public void setSubHeading(String subHeading) {
this.subHeading = subHeading;
}
}
And this is the XML layout of the main fragment:
<RelativeLayout 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"
android:padding="16dp"
android:background="#color/dialog_background"
android:orientation="vertical"
tools:context="iulms.iunc.edu.pk.iqraiulms.GraduatingSurvey"
android:id="#+id/main_layout">
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/graduate_list"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="#+id/btn_graduate_submit"
/>
<Button
android:id="#+id/btn_graduate_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="submit"
android:layout_alignParentBottom="true"
/>
</RelativeLayout>
These are the layouts for the different types of rows in listview
Row type 1:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/dialog_background"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingTop="16dp">
<TextView
android:id="#+id/graduate_question"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:text="1. Here comes questions?"
android:textSize="13dp" />
<!-- <EditText
android:id="#+id/graduate_comment"
style="#style/GraduateTextBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:background="#drawable/textbox"
android:ems="10"
android:hint="Comment"
android:inputType="textMultiLine"
android:lines="3" />-->
<LinearLayout
android:id="#+id/graduate_choices"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RadioGroup
android:id="#+id/graduate_radioGroup"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RadioButton
android:id="#+id/graduate_sAgree"
style="#style/GraduateRadioButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/checkbox_selector"
android:button="#android:color/transparent"
android:checked="false"
android:text="Strongly Agree" />
<RadioButton
android:id="#+id/graduate_agree"
style="#style/GraduateRadioButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/checkbox_selector"
android:button="#android:color/transparent"
android:checked="false"
android:text="Agree" />
<RadioButton
android:id="#+id/graduate_uncertain"
style="#style/GraduateRadioButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/checkbox_selector"
android:button="#android:color/transparent"
android:checked="false"
android:text="Uncertain"
/>
<RadioButton
android:id="#+id/graduate_disagree"
style="#style/GraduateRadioButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/checkbox_selector"
android:button="#android:color/transparent"
android:checked="false"
android:text="Disagree" />
<RadioButton
android:id="#+id/graduate_sDisagree"
style="#style/GraduateRadioButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/checkbox_selector"
android:button="#android:color/transparent"
android:checked="false"
android:text="Strongly Disagree" />
</RadioGroup>
</LinearLayout>
</LinearLayout>
Row type 2
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/dialog_background"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingTop="16dp">
<TextView
android:id="#+id/graduate_question"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:text="1. Here comes questions?"
android:textSize="13dp" />
<EditText
android:id="#+id/graduate_comment"
style="#style/GraduateTextBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:background="#drawable/textbox"
android:ems="10"
android:hint="Comment"
android:inputType="textMultiLine"
android:lines="3" />
</LinearLayout>
Row type 3:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/dialog_background"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingTop="16dp">
<TextView
android:id="#+id/graduate_question"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:text="1. Here comes questions?"
android:textSize="15dp"
android:textColor="#color/primary_dark"/>
</LinearLayout>
How can I retrieve the data submitted in the main fragment?
Thanks
For this You can create a custom class with row values like,
Arraylist<CustomClass> mnewList = new ArrayList();
Class CustomClass
{
private String edValues,
private int rowId,
}
etc.
Then Implement on change listener for radio button in that add/remove current selected items to that custom list.

Categories

Resources