Почему обработчик события не работает через include?
Нужна in-app клавиатура,чтобы спокойно мог из разных активити подключать. Код следующий:
Клавиатура, задаем кнопки и т.д.:
public class MyKeyboard extends ConstraintLayout implements View.OnClickListener {
private Button button_q,
button_w,
button_e,
button_r,
button_t,
button_y,
button_u,
button_i,
button_o,
button_p,
button_a,
button_s,
button_d,
button_f,
button_g,
button_h,
button_j,
button_k,
button_l,
button_z,
button_x,
button_c,
button_v,
button_b,
button_n,
button_m,
buttonDelete, buttonEnter;
private SparseArray<String> keyValues = new SparseArray<>();
private InputConnection inputConnection;
public MyKeyboard(Context context) {
super(context);
init();
}
private void init() {
button_q = (Button) findViewById(R.id.button_q);
button_q.setOnClickListener(this);
button_w = (Button) findViewById(R.id.button_w);
button_w.setOnClickListener(this);
button_e = (Button) findViewById(R.id.button_e);
button_e.setOnClickListener(this);
button_r = (Button) findViewById(R.id.button_r);
button_r.setOnClickListener(this);
button_t = (Button) findViewById(R.id.button_t);
button_t.setOnClickListener(this);
button_y = (Button) findViewById(R.id.button_y);
button_y.setOnClickListener(this);
button_u = (Button) findViewById(R.id.button_u);
button_u.setOnClickListener(this);
button_i = (Button) findViewById(R.id.button_i);
button_i.setOnClickListener(this);
button_o = (Button) findViewById(R.id.button_o);
button_o.setOnClickListener(this);
button_p = (Button) findViewById(R.id.button_p);
button_p.setOnClickListener(this);
button_a = (Button) findViewById(R.id.button_a);
button_a.setOnClickListener(this);
button_s = (Button) findViewById(R.id.button_s);
button_s.setOnClickListener(this);
button_d = (Button) findViewById(R.id.button_d);
button_d.setOnClickListener(this);
button_f = (Button) findViewById(R.id.button_f);
button_f.setOnClickListener(this);
button_g = (Button) findViewById(R.id.button_g);
button_g.setOnClickListener(this);
button_h = (Button) findViewById(R.id.button_h);
button_h.setOnClickListener(this);
button_h = (Button) findViewById(R.id.button_h);
button_h.setOnClickListener(this);
button_j = (Button) findViewById(R.id.button_j);
button_j.setOnClickListener(this);
button_k = (Button) findViewById(R.id.button_k);
button_k.setOnClickListener(this);
button_l = (Button) findViewById(R.id.button_l);
button_l.setOnClickListener(this);
button_z = (Button) findViewById(R.id.button_z);
button_z.setOnClickListener(this);
button_x = (Button) findViewById(R.id.button_x);
button_x.setOnClickListener(this);
button_c = (Button) findViewById(R.id.button_c);
button_c.setOnClickListener(this);
button_v = (Button) findViewById(R.id.button_v);
button_v.setOnClickListener(this);
button_b = (Button) findViewById(R.id.button_b);
button_b.setOnClickListener(this);
button_n = (Button) findViewById(R.id.button_n);
button_n.setOnClickListener(this);
button_m = (Button) findViewById(R.id.button_m);
button_m.setOnClickListener(this);
buttonDelete = (Button) findViewById(R.id.button_delete);
buttonDelete.setOnClickListener(this);
buttonEnter = (Button) findViewById(R.id.button_space);
buttonEnter.setOnClickListener(this);
keyValues.put(R.id.button_q, "q");
keyValues.put(R.id.button_w, "w");
keyValues.put(R.id.button_e, "e");
keyValues.put(R.id.button_r, "r");
keyValues.put(R.id.button_t, "t");
keyValues.put(R.id.button_y, "y");
keyValues.put(R.id.button_u, "u");
keyValues.put(R.id.button_i, "i");
keyValues.put(R.id.button_o, "o");
keyValues.put(R.id.button_p, "p");
keyValues.put(R.id.button_a, "a");
keyValues.put(R.id.button_s, "s");
keyValues.put(R.id.button_d, "d");
keyValues.put(R.id.button_f, "f");
keyValues.put(R.id.button_g, "g");
keyValues.put(R.id.button_h, "h");
keyValues.put(R.id.button_j, "j");
keyValues.put(R.id.button_k, "k");
keyValues.put(R.id.button_l, "l");
keyValues.put(R.id.button_z, "z");
keyValues.put(R.id.button_x, "x");
keyValues.put(R.id.button_c, "c");
keyValues.put(R.id.button_v, "v");
keyValues.put(R.id.button_b, "b");
keyValues.put(R.id.button_n, "n");
keyValues.put(R.id.button_m, "m");
keyValues.put(R.id.button_space, " ");
}
@Override
public void onClick(View view) {
if (inputConnection == null)
return;
if (view.getId() == R.id.button_delete) {
CharSequence selectedText = inputConnection.getSelectedText(0);
if (TextUtils.isEmpty(selectedText)) {
inputConnection.deleteSurroundingText(1, 0);
} else {
inputConnection.commitText("", 1);
}
} else {
String value = keyValues.get(view.getId());
inputConnection.commitText(value, 1);
}
}
public void setInputConnection(InputConnection ic) {
inputConnection = ic;
}
}
Активити, где требуется клавиатура:
package com.tsvetkovopozdal.lalaeng;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.speech.tts.Voice;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Spanned;
import android.text.TextWatcher;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import android.text.InputType;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.widget.EditText;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.widget.Toast;
import java.util.Locale;
public class WordConstructor extends AppCompatActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.word_constructor);
Bundle argumets = getIntent().getExtras();
final String name = argumets.get("text").toString();
TextView a = findViewById(R.id.word_constructor_hello);
a.setText(name);
final EditText editText = (EditText) findViewById(R.id.editText);
editText.setRawInputType(InputType.TYPE_CLASS_TEXT);
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(name.length())}); this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
MyKeyboard keyboard = new MyKeyboard(getApplicationContext());
InputConnection ic = editText.onCreateInputConnection(new EditorInfo());
keyboard.setInputConnection(ic);
}
}
Подключается через include
<include
android:id="@+id/keyboard"
layout="@layout/keyboard"/>
Суть проблемы: при вызове init() из конструктора класса MyKeyboard студия выдает следующую ошибку
Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
Порывшись в сети, нашел посты, где у людей данная ошибка возникала при использовании findViewById до вызова методов onCreate() и setContentView(), это вроде бы не мой случай, так как создаю экземпляр класса после отрисовки view и в самом методе onCreate. Спустя половину дня поисков, зачем-то все таки заменил конструктор класса MyKeyboard на метод onCreate и вызвал init() из него, в итоге ошибка пропала, все запускается, но теперь в метод init() не заходит(дебажил toast'ом).
Вопрос: как в данном случае повесить слушаетели на кнопки клавиатуры, чтобы все работало через include? То есть чтобы не переносить логику клавиатуры, слушателей и т.д. в код активити.
Ответы (1 шт):
Ты пытаешься обратиться к вьюшкам, которые лежат в .xml, но твоя вьюшка с клавиатурой не знает ничего о том самом .xml, поэтому тебе нужно ее заинфлейтить.
Для этого в начало init() добавь следующее:
LayoutInflater.from(getContext()).inflate(R.layout.твой_айди_разметки, this, true)
Кроме того, лейаут разметки желательно обернуть не в ConstraintLayout, а в merge, это избавит тебя от лишней прослойки из вьюх на этапе инфлейтинга.
И ещё -- использовать Constraint на вьюшке с клавиатурой, наверное, не лучшая идея, ибо получается слишком много связей, и measure/layout pass может занять довольно много времени.