Как заставить OnClickListener работать с настраиваемым представлением с помощью RelativeLayout?
Вопрос
Здравствуйте,
Я создал пользовательский вид с RelativeLayout, чтобы использовать его как пользовательскую кнопку изображения.
Пока он работает (PIC2), и даже когда я нажимаю на него (используя GoogleTV Remote), представление успешно изменяет его состояние на PIC3 (благодаря android: duplicateParentState = "true" )
Но, к сожалению, onClickListener не срабатывает (не имеет значения, если я нажму кнопку View с помощью кнопки "OK" на пульте дистанционного управления, или я использую сенсорную панель.)
Мне действительно нужно такое же поведение, как и обычная кнопка.
Как это сделать? Я уже потратил несколько часов на поиск Google и StackOverflow... (BTW при настройке android: clickable = "false" для RelativeLayout, OnClickListener работает, но только когда я использую указатель мыши (Touchpad), а затем фокус и состояние (рис. 3) не отображается)
Фотографии
Pic1
![Custom View Normal]()
pic2
![Custom View Focused]()
pic3
![Custom View Clicked]()
Код
rounded_button.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="false">
<TextView
android:id="@+id/caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="30dp"
android:background="@drawable/btn_rounded_corners"
android:paddingLeft="25dp"
android:textSize="15sp"
android:duplicateParentState="true"/>
<ImageView
android:id="@+id/icon"
style="@style/Menu_Button"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginRight="-50dp"
android:layout_toLeftOf="@id/caption"
android:background="@drawable/btn_main_menu_back_shape"
tools:ignore="ContentDescription"
android:duplicateParentState="true" />
RoundedButton.java
public class RoundedButton extends RelativeLayout {
private String label;
private int icon;
/**
* @param context
*/
public RoundedButton(Context context)
{
super(context);
initAttributes(context, null);
}
/**
* @param context
* @param attrs
*/
public RoundedButton(Context context, AttributeSet attrs)
{
super(context, attrs);
initAttributes(context, attrs);
}
/**
* @param context
* @param attrs
* @param defStyle
*/
public RoundedButton(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
initAttributes(context, attrs);
}
private void initAttributes(Context context, AttributeSet attrs)
{
LayoutInflater.from(context).inflate(R.layout.rounded_button, this, true);
TypedArray a =
context.obtainStyledAttributes(attrs, R.styleable.RoundedButton);
final int N = a.getIndexCount();
for (int i = 0; i < N; ++i)
{
int attr = a.getIndex(i);
switch (attr)
{
case R.styleable.RoundedButton_text:
setLabel(a.getString(attr));
break;
case R.styleable.RoundedButton_icon:
setIcon(a.getResourceId(attr, 0));
break;
}
}
a.recycle();
}
public String getLabel()
{
return this.label;
}
public void setLabel(final String label)
{
this.label = label;
((TextView)findViewById(R.id.caption)).setText(this.label);
}
/**
* @return the icon
*/
public int getIcon()
{
return icon;
}
/**
* @param icon the icon to set
*/
public void setIcon(int icon)
{
this.icon = icon;
((ImageView)findViewById(R.id.icon)).setImageResource(this.icon);
}
}
Соответствующая часть activity_main.xml
<eu.test.custom_views.RoundedButton
android:id="@+id/custombutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:icon="@drawable/hand_icon_green_left"
custom:text="Normal state" />
Основная деятельность
public class MainActivity extends Activity implements OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((RoundedButton) findViewById(R.id.custombutton)).setOnClickListener(this);
}
@Override
public void onClick(View arg0) {
if(arg0.getId() == R.id.custombutton) { Toast.makeText(this, "Clicked", Toast.LENGTH_SHORT).show(); }
}
}
Ответы
Ответ 1
Я получил его сейчас.. решение настолько просто, что потребовалось некоторое время; -)
Решение
Заменить dispatchKeyEvent(KeyEvent event)
в RoundedButton.java и реализовать собственный OnClickListener. Затем напишите общедоступную функцию setOnClickListener
...
private OnClickListener listener;
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP) {
if(listener != null) listener.onClick(this);
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if(event.getAction() == KeyEvent.ACTION_UP && (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER || event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
if(listener != null) listener.onClick(this);
}
return super.dispatchKeyEvent(event);
}
public void setOnClickListener(OnClickListener listener) {
this.listener = listener;
}
Работа RoundedButton.java
public class RoundedButton extends RelativeLayout
{
private OnClickListener listener;
private String label;
private int icon;
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP) {
if(listener != null) listener.onClick(this);
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if(event.getAction() == KeyEvent.ACTION_UP && (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER || event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
if(listener != null) listener.onClick(this);
}
return super.dispatchKeyEvent(event);
}
public void setOnClickListener(OnClickListener listener) {
this.listener = listener;
}
/**
* @param context
*/
public RoundedButton(Context context)
{
super(context);
initAttributes(context, null);
}
/**
* @param context
* @param attrs
*/
public RoundedButton(Context context, AttributeSet attrs)
{
super(context, attrs);
initAttributes(context, attrs);
}
/**
* @param context
* @param attrs
* @param defStyle
*/
public RoundedButton(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
this.setClickable(true);
this.setEnabled(true);
this.setFocusable(true);
this.setFocusableInTouchMode(true);
initAttributes(context, attrs);
}
private void initAttributes(Context context, AttributeSet attrs)
{
LayoutInflater.from(context).inflate(R.layout.rounded_button, this, true);
TypedArray a =
context.obtainStyledAttributes(attrs, R.styleable.RoundedButton);
final int N = a.getIndexCount();
for (int i = 0; i < N; ++i)
{
int attr = a.getIndex(i);
switch (attr)
{
case R.styleable.RoundedButton_text:
setLabel(a.getString(attr));
break;
case R.styleable.RoundedButton_icon:
setIcon(a.getResourceId(attr, 0));
break;
}
}
a.recycle();
}
public String getLabel()
{
return this.label;
}
public void setLabel(final String label)
{
this.label = label;
((TextView)findViewById(R.id.caption)).setText(this.label);
}
/**
* @return the icon
*/
public int getIcon()
{
return icon;
}
/**
* @param icon the icon to set
*/
public void setIcon(int icon)
{
this.icon = icon;
((ImageView)findViewById(R.id.icon)).setImageResource(this.icon);
}
}
Ответ 2
Я создавал экземпляры своего пользовательского представления (который наследуется от RelativeLayout
) в RecyclerView.Adapter
и раздувает list_item.xml
в каждый новый экземпляр, а затем присоединяет мой слушатель в методе onBindViewHolder()
, но даже если в теории Я делал все правильно, он не работал, пока я не удалял атрибут android:clickable="true"
из корневого макета list_item.xml
(мой пользовательский вид).
Ответ 3
public class CustomView extends RelativeLayout implements OnClickListener {
private OnClickListener clickListener;
public CustomView(Context context) {
super(context);
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
super.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (clickListener != null) {
clickListener.onClick(v);
}
}
@Override
public void setOnClickListener(@Nullable OnClickListener l) {
this.clickListener = l;
}
}