3

I'm trying to make a dictionary with two TextViews - 1 for the word, 1 for the translation. On long press, an edit button will popup that will show an alert dialog on click. The alert dialog takes two inputs, new word and new translation, edits the old word, and sets the TextView to these words.

The problem is that the setText in the alert dialog doesn't change the UI (setBGcolor and setAllCaps work though). Only after resetting the Activity in which I use the adapter do the changes show.

public class DictionaryAdapter extends ArrayAdapter<String> {

private LayoutInflater inflater;
private int layout;
private Map<String, String> dict;
private boolean[] visibleButtons;
private Context mContext;

static class ViewHolder {
    TextView word;
    TextView translation;
    FloatingActionButton edit;
}

public DictionaryAdapter(Context context, int layout, Map<String, String> source) {
    super(context, layout, new ArrayList<>(source.keySet()));
    mContext = context;
    inflater = LayoutInflater.from(context);
    this.layout = layout;
    dict = source;
    visibleButtons = new boolean[dict.size()];
}

@NonNull
@Override
public View getView(final int position, @Nullable View convertView, @NonNull final ViewGroup parent) {
    final String word = getItem(position);
    final String translation = dict.get(word);
    final ViewHolder holder;
    if(convertView == null) {
        convertView = inflater.inflate(layout, null, false);
        holder = new ViewHolder();
        holder.word = (TextView) convertView.findViewById(R.id.dictWord);
        holder.translation = (TextView) convertView.findViewById(R.id.dictTranslation);
        holder.edit = convertView.findViewById(R.id.editTranslation);
        convertView.setTag(holder);
    }
    else {
        holder = (ViewHolder)convertView.getTag();
    }

    holder.word.setText(word);
    holder.translation.setText(translation);
    if(position < visibleText.length) {

        if (visibleButtons[position]) {
            holder.edit.setVisibility(View.VISIBLE);
        } else {
            holder.edit.setVisibility(View.GONE);
        }
    }

    holder.word.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View view) {
            if(holder.edit.getVisibility() == View.VISIBLE) {
                holder.edit.setVisibility(View.GONE);
                visibleButtons[position] = false;
            }
            else {
                holder.edit.setVisibility(View.VISIBLE);
                visibleButtons[position] = true;
            }
            return true;
        }
    });

    holder.edit.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
            View showDialog = inflater.inflate(R.layout.add_new_word_popup, parent, false);

            final EditText editTextWord = (EditText) showDialog.findViewById(R.id.wordInput);
            final EditText editTextTranslation = (EditText) showDialog.findViewById(R.id.translationInput);
            Button addWordButton = (Button) showDialog.findViewById(R.id.button_confirm_word);
            addWordButton.setText(R.string.edit_WordTrans_button);

            builder.setView(showDialog);
            final AlertDialog dialog = builder.create();
            dialog.show();

            addWordButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    final String wordInput = editTextWord.getText().toString();
                    final String translationInput = editTextTranslation.getText().toString();
                    boolean addable = true;
                    if(wordInput.replaceAll("\\s+","").isEmpty()) {
                        Toast.makeText(mContext, R.string.no_word_err, Toast.LENGTH_SHORT).show();
                        addable = false;
                    }
                    if (translationInput.replaceAll("\\s+","").isEmpty()) {
                        Toast.makeText(mContext, R.string.no_translation_err, Toast.LENGTH_SHORT).show();
                        addable = false;
                    }
                    if(addable) {
                        editWord(holder.word.getText().toString(), wordInput, translationInput);
                        holder.word.setText(wordInput);
                        holder.translation.setText(translationInput);
                        notifyDataSetChanged();
                        Toast.makeText(mContext, R.string.edited_word_msg, Toast.LENGTH_SHORT).show();
                        dialog.dismiss();
                    }
                }
            });

        }
    });

    return convertView;
}

private void editWord(String oldWord, String newWord, String newTranslation) {
    MainApplication.getDataUtils().editWordInDict(mContext, DictionaryActivity.currentDictionaryName,
            oldWord, newWord, newTranslation); // edits the word in sharedPreferences
    dict.remove(oldWord);
    dict.put(newWord, newTranslation);
    notifyDataSetChanged();
}

What I've tried but didn't quite work:

This updated the TextView. But when I tried to edit another word, the first word showed the original word again.

holder.word.post(new Runnable() {
    @Override
    public void run() {
        holder.word.setText(wordInput);
        holder.translation.setText(translationInput);
    }
});

This had no effect at all:

((Activity)mContext).runOnUiThread(new Runnable() {
    @Override
    public void run() {
        holder.word.setText(wordInput);
        holder.translation.setText(translationInput);
    }
});

I also tried calling this method (same effect as with holder.word.post method):

private void changeText(final ViewHolder holder, final String newWord, final String newTranslation) {
final Runnable mUpdateText = new Runnable() {
    public void run() {
        holder.word.setText(newWord);
        holder.translation.setText(newTranslation);
    }
};
mHandler.post(mUpdateText);
}

This is the dialog layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:paddingStart="10dip">

<TextView
    android:id="@+id/dictWord"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_alignParentStart="true"
    android:layout_alignParentTop="true"
    android:background="?android:attr/selectableItemBackground"
    android:clickable="true"
    android:focusable="true"
    android:longClickable="true"
    android:textSize="25sp" />

<TextView
    android:id="@+id/dictTranslation"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_alignParentStart="true"
    android:layout_below="@+id/dictWord"
    android:background="?android:attr/selectableItemBackground"
    android:textSize="25sp"
    android:textStyle="bold"/>

<android.support.design.widget.FloatingActionButton
    android:id="@+id/editTranslation"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_alignParentEnd="true"
    android:layout_alignParentTop="true"
    android:layout_marginEnd="58dp"
    android:clickable="true"
    android:focusable="true"
    android:visibility="gone"
    app:backgroundTint="@android:color/transparent"
    app:srcCompat="@android:drawable/ic_menu_edit" />
</RelativeLayout>
Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
Tom
  • 31
  • 1
  • If I understand correctly you don't need to do a setText directly in the view holder. You should can only notifyDataSetChanged() and the adapter will refresh with the right textView. Never manipulate directly the holder you cannot have the warranty that is the right one. – Alessandro Verona May 11 '18 at 07:22
  • The code already has notifyDataSetChanged() right after editting the word and after setText too. Result stays the same. – Tom May 11 '18 at 09:28
  • ok, maybe can help to figure out the problem with this: remove if(convertView == null) {} and call always convertView = inflater.inflate(layout, null, false); (only a try) – Alessandro Verona May 11 '18 at 09:31
  • Without if(convertView == null) {} the scrolling will not be smooth, which is mandatory for my app, since the listView will contain a lot of words. – Tom May 11 '18 at 09:36
  • yes sure but fix the problem? – Alessandro Verona May 11 '18 at 09:37
  • No, it doesn't, just tried. Thanks for the advice anyway! – Tom May 11 '18 at 09:39

0 Answers0