Я разработал собственное составное представление, в котором есть Button и ProgressBar. Я использую databinding в своем приложении. Составное представление не принимает событие onClick, как решить эту проблему?
<com.ui.custom.LoadingButton
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:background = "@color/bg_color"
android:onClick = "@{()->viewModel.onNextClick()}"
android:text = "@string/next"
android:textColor = "@color/white"
app:isLoading = "@{viewModel.isLoading}" />
Расположение кнопки загрузки:
<?xml version = "1.0" encoding = "utf-8"?>
<layout xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:app = "http://schemas.android.com/apk/res-auto">
<data>
</data>
<FrameLayout
android:id = "@+id/parentFrame"
android:layout_width = "match_parent"
android:layout_height = "wrap_content">
<Button
android:id = "@+id/button"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:background = "?android:selectableItemBackground"
android:textSize = "@dimen/btn_text_size" />
<com.wang.avi.AVLoadingIndicatorView
android:id = "@+id/loading_indicator"
android:layout_width = "@dimen/btn_loading_indicator"
android:layout_height = "@dimen/btn_loading_indicator"
android:layout_gravity = "center"
android:elevation = "@dimen/cardview_default_elevation"
app:indicatorName = "LineSpinFadeLoaderIndicator" />
</FrameLayout>
</layout>
Или, если я использую атрибут android onClick, как я могу получить его в TypedArray? Так что я могу настроить его для просмотра программно.
<declare-styleable name = "LoadingButton">
<attr name = "isLoading" format = "boolean" />
<attr name = "android:text" />
<attr name = "android:textColor" />
<attr name = "android:background" />
<attr name = "android:onClick" />
</declare-styleable>
LoadingButton java
@BindingMethods({
@BindingMethod(type = LoadingButton.class, attribute = "onLoadingButtonClick", method = "onLoadingButtonClick"),
})
public class LoadingButton extends LinearLayout implements View.OnClickListener {
private Context mContext;
private int background, textColor;
private boolean isLoading;
private String btnText;
private LayoutLoadingBtnBinding itemViewBinding;
private OnLoadingButtonListener listener;
public LoadingButton(Context context) {
super(context);
initializeView(context, null, 0);
}
public LoadingButton(Context context, AttributeSet attrs) {
super(context, attrs);
initializeView(context, attrs, 0);
}
public LoadingButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initializeView(context, attrs, defStyleAttr);
}
private void initializeView(Context context, AttributeSet attrs, int defStyleAttr) {
mContext = context;
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LoadingButton, defStyleAttr, 0);
try {
background = array.getColor(R.styleable.LoadingButton_android_background, Integer.MAX_VALUE);
textColor = array.getColor(R.styleable.LoadingButton_android_textColor, Integer.MAX_VALUE);
btnText = array.getString(R.styleable.LoadingButton_android_text);
isLoading = array.getBoolean(R.styleable.LoadingButton_isLoading, false);
// Method onClick = array.getValue(R.styleable.LoadingButton_android_onClick);
} finally {
array.recycle();
}
itemViewBinding = LayoutLoadingBtnBinding.inflate(LayoutInflater.from(mContext), this, true);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// setOnClickListener(this::onClick);
setValues();
}
private void setValues() {
try {
if (background != Integer.MAX_VALUE)
itemViewBinding.parentFrame.setBackgroundColor(background);
if (background != Integer.MAX_VALUE) {
itemViewBinding.button.setTextColor(textColor);
itemViewBinding.loadingIndicator.setIndicatorColor(textColor);
}
itemViewBinding.button.setText(btnText);
updateLoadingViews();
} catch (Exception e) {
e.printStackTrace();
}
}
private void updateLoadingViews() {
itemViewBinding.button.setVisibility(isLoading ? INVISIBLE : VISIBLE);
itemViewBinding.loadingIndicator.setVisibility(isLoading ? VISIBLE : GONE);
}
public void setLoading(boolean isLoading) {
if (this.isLoading != isLoading) // update only if loading state is changed
{
this.isLoading = isLoading;
updateLoadingViews();
}
}
public void setOnLoadingButtonClick(OnLoadingButtonListener listener) {
AppLogger.d("usm_loading_btn_0", "setOnLoadingButtonClick is called: listener= " + (listener != null));
this.listener = listener;
}
@Override
public void onClick(View view) {
AppLogger.d("usm_loading_btn_1", "onClick is called");
if (listener != null) {
listener.onLoadingButtonClick();
}
}
public interface OnLoadingButtonListener {
void onLoadingButtonClick();
}
}
Сам родитель - LinearLayout, я хочу реализовать onClick вместо его дочернего элемента или дочернего элемента без доступа к идентификаторам
Вы не можете использовать этот способ
<attr name = "android:onClick" />
Попробуйте использовать BindingMethods
@BindingMethods({
@BindingMethod(type = LoadingButton.class, attribute = "onLoadingButtonClick", method = "onLoadingButtonClick"),
})
public class LoadingButton extends YOUR_ROOT_VIEW implements View.OnClickListener {
// your item view class.
private OnLoadingButtonListener listener;
public void setOnLoadingButtonClick(OnLoadingButtonListener listener) {
this.listener = listener;
}
@Override
public void onClick(View view) {
if (listener != null) {
listener.onLoadingButtonClick();
}
}
public interface OnLoadingButtonListener {
void onLoadingButtonClick();
}
}
и в вашем макете
<com.ui.custom.LoadingButton
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:background = "@color/bg_color"
android:onLoadingButtonClick = "@{()->viewModel.onNextClick()}"
android:text = "@string/next"
android:textColor = "@color/white"
app:isLoading = "@{viewModel.isLoading}" />
ОБНОВЛЕНИЕ 1
Если ваш onClick() не работает, удалите его и попробуйте использовать этот способ.
private void initializeView(Context context, AttributeSet attrs, int defStyleAttr) {
mContext = context;
TypedArray array =
context.obtainStyledAttributes(attrs, R.styleable.LoadingButton, defStyleAttr, 0);
try {
background =
array.getColor(R.styleable.LoadingButton_android_background, Integer.MAX_VALUE);
textColor =
array.getColor(R.styleable.LoadingButton_android_textColor, Integer.MAX_VALUE);
btnText = array.getString(R.styleable.LoadingButton_android_text);
isLoading = array.getBoolean(R.styleable.LoadingButton_isLoading, false);
// Method onClick = array.getValue(R.styleable.LoadingButton_android_onClick);
} finally {
array.recycle();
}
itemViewBinding =
LayoutLoadingBtnBinding.inflate(LayoutInflater.from(mContext), this, true);
itemViewBinding.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onLoadingButtonClick();
}
}
});
}
Спасибо за хорошее решение. Но мой onClick не звонит, хотя setOnLoadingButtonClick работает нормально.
все равно ... onClick не звонит
попробуйте еще раз с itemViewBinding.button, см. мой ответ на обновление
Он работает при нажатии кнопки, можем ли мы заставить его работать в родительском представлении?
Я думаю, потому что вы используете кнопку с соответствующим родительским макетом, поэтому родительский вид не может получить прослушиватель кликов
точка, поэтому он должен работать, если мы отключим щелчок дочернего представления. И как это сделать без привязки данных?
да, вы можете использовать LayoutInflater.from(getContext()).inflate(R.layout.layout_loading_btn, this, true); для надувания макета
Я имею в виду, что такое onClick
Не могли бы вы проверить этот вопрос? stackoverflow.com/questions/51096414/…
Вы пробовали использовать идентификатор кнопки для реализации прослушивателя onClick?