Ответ 1
Вы можете поместить прозрачный View
поверх Switch
и переключить его включенное состояние напротив коммутатора и показать сообщение при нажатии на этот наложенный View
.
Я хочу иметь возможность реагировать на событие щелчка на отключенном коммутаторе, возможно ли это?
У меня есть переключатель, который не включен, пока пользователь не заполнит какую-либо информацию, поэтому он выглядит так:
Я хочу пригласить пользователя заполнить эту информацию, если они нажмут на отключенный переключатель с диалоговым окном, например:
mySwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!userInfo.isFilled){
new AlertDialog.Builder(MainActivity.this)
.setTitle("Fill out info first!")
.setMessage("You must first fill out info before turning on this featurel")
.setNeutralButton("Okay", null)
.show();
}
}
});
Однако onClick()
не запускается, когда я нажимаю на отключенный переключатель, так как я могу получить, когда пользователь нажимает на него?
Вы можете поместить прозрачный View
поверх Switch
и переключить его включенное состояние напротив коммутатора и показать сообщение при нажатии на этот наложенный View
.
Вы можете установить onTouchListener
и отредактировать ссылку boolean
(например, isToggleEnable
) относительно предыдущих действий пользователя:
mySwitch.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(!isToggleEnable){
//Taost here
}
//If isToggleEnable = false on return OnClickListener won't be called
return isToggleEnable;
}
});
Из View.java исходный код,
public boolean dispatchTouchEvent(MotionEvent event) {
// If the event should be handled by accessibility focus first.
if (event.isTargetAccessibilityFocus()) {
// We don't have focus or no virtual descendant has it, do not handle the event.
if (!isAccessibilityFocusedViewOrHost()) {
return false;
}
// We have focus and got the event, then use normal event dispatch.
event.setTargetAccessibilityFocus(false);
}
boolean result = false;
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Defensive cleanup for new gesture
stopNestedScroll();
}
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
if (!result && mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
// Clean up after nested scrolls if this is the end of a gesture;
// also cancel it if we tried an ACTION_DOWN but we didn't want the rest
// of the gesture.
if (actionMasked == MotionEvent.ACTION_UP ||
actionMasked == MotionEvent.ACTION_CANCEL ||
(actionMasked == MotionEvent.ACTION_DOWN && !result)) {
stopNestedScroll();
}
return result;
}
флаг enabled гарантирует, что UnhandledEvents потребляется, но не передается вместе с прослушивателями, тем самым минуя весь ваш возможный код. Таким образом, невозможно прослушать события в отключенном виде.
Тем не менее, ваши варианты:
setClickable(false)
и использовать события касания)Попробуйте установить setFocusable(false)
и setEnabled(true)
на свой коммутатор. Таким образом, события щелчка будут запущены, пока переключатель все еще будет отключен. Взято из этого ответа.
Когда он отключен, setEnabled(false)
, эти слушатели не будут работать.
Попробуйте так: не отключайте его, используйте setOnCheckedChangeListener
и проверяйте его заполнение:
использовать setOnCheckedChangeListener
switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isEntryFilled) {
buttonView.setChecked(false);
// your alert dialog
} else {
}
}
});
это снова проверяет его на выключение и выдает ваше предупреждение, пока не будет выполнено isEntryFilled
.
ИЗМЕНИТЬ
ИЛИ вместо setEnabled(false)
используйте setClickable(false)
или android:clickable="false"
, так как docs говорят, что setClickable()
привязан к событиям click-events.
и вместо OnClickListener
попробуйте OnTouchListener
. Он зарегистрирует ваше нажатие на касание (и игнорирует ваше касание), так как щелчок состоит из вниз + вверх.
switch.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (!isEntryFilled) {
buttonView.setChecked(false);
// your alert dialog
}
return false;
}
});
затем в другом месте, где вы проверяете isEntryFilled
, активируйте свой переключатель с помощью switch.setClickable(true)
mySwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isClick()){
//Your Valid Code
}else{
//Make our switch to false
new AlertDialog.Builder(MainActivity.this)
.setTitle("Fill out info first!")
.setMessage("You must first fill out info before turning on this featurel")
.setNeutralButton("Okay", null)
.show();
}
}
});
public Boolean isClick(){
//check condition that user fill details or not
//if yes then return true
// else return false
}
Пусть Parent View
перехватывает ClickEvent
или TouchEvent
s, когда его обнаружение проверяет, отключен ли прием View
, и выполняйте то, что вам нужно сделать.
Edit
"он не работает при отключении?"
попробуйте эти коды, я использую LinearLayout
для легкого выбора. но в целом он должен дать вам пример
это полный пример
XML
<FrameLayout 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:layout_marginTop="70dp"
android:background="#273746">
<FrameLayout
android:layout_width="match_parent"
android:id="@+id/ass"
android:background="@drawable/abc_popup_background_mtrl_mult"
android:layout_height="match_parent">
</FrameLayout>
MainActivity onCreate
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_entry_screen);
FrameLayout fl = (FrameLayout)findViewById(R.id.ass);
Test t = new Test(this);
FrameLayout.LayoutParams lp = (LayoutParams) fl.getLayoutParams();
lp.height = LayoutParams.MATCH_PARENT;
lp.width = LayoutParams.MATCH_PARENT;
t.setOrientation(LinearLayout.VERTICAL);
t.setLayoutParams(lp);
fl.addView(t);
t.setBackgroundColor(Color.YELLOW);
Button b = new Button(this);
b.setText("patricia");
t.addView(b);
b = new Button(this);
b.setText("monica");
t.addView(b);
b = new Button(this);
b.setText("rebecca");
t.addView(b);
}
Test.java
public class Test extends LinearLayout {
public Test(Context context) {
super(context);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
StringBuilder sb = new StringBuilder();
sb.append("intercept \n\r");
int x = (int)event.getX(),
y= (int)event.getY();
for(int i =0; i< getChildCount(); i++){
int[] pos = new int[]{getChildAt(i).getLeft(),getChildAt(i).getTop(),
getChildAt(i).getMeasuredWidth(),
getChildAt(i).getMeasuredHeight()};
sb.append(getChildAt(i).getLeft()+", ");
sb.append(getChildAt(i).getTop()+", ");
sb.append(getChildAt(i).getMeasuredWidth()+", ");
sb.append(getChildAt(i).getMeasuredHeight());
sb.append("\n\r");
sb.append(isInBounds(pos, x, y));
sb.append("\n\r");
}
sb.append("x is ");
sb.append(x);
sb.append("y is ");
sb.append(y);
Toast.makeText(getContext(),sb.toString() , Toast.LENGTH_LONG).show();
return super.onInterceptTouchEvent(event);
}
private boolean isInBounds(int[] dimen, int x, int y){
return ((x >= dimen[0] && x < (dimen[0] + dimen[2]))
&& (y >= dimen[1] && y < (dimen[1] + dimen[3])));
}
}
Теперь тот, который вы нажмете, будет проверяться как истинный, то есть ребенок, теперь, когда он проверяет, что он прав, вы можете сделать что-то вроде этого
View v = getchildAt(pos);
//its the one that is tapped or clicked
if(!v.isEnabled()){
//this is the guy you want now, do what you want to do
для события click Я не пытаюсь это сделать, но вы можете просто сделать View.performClick()
или поместить свой диалог в класс ViewGroup
и вызвать его
на самом деле вы можете использовать View..getClipBounds()
для сохранения себя из массива int
Установите отключенные переключатели на прослушивателе кликов, чтобы изменить прослушиватели других переключателей. Например:
Switch s = (Switch) findViewById(R.id.SwitchID);
if (s != null) {
s.setOnCheckedChangeListener(this);
}
/* ... */
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Toast.makeText(this, "The Switch is " + (isChecked ? "on" : "off"),
Toast.LENGTH_SHORT).show();
if(isChecked) {
//do stuff when Switch is ON
//this is where you set your normal state OnClickListner
} else {
mySwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!userInfo.isFilled){
new AlertDialog.Builder(MainActivity.this)
.setTitle("Fill out info first!")
.setMessage("You must first fill out info before turning on this featurel")
.setNeutralButton("Okay", null)
.show();
}
}
});
}
}
Я предполагаю, что вы отключили коммутатор, используя switch.setEnabled(false). Если это так, событие onclick не будет запускаться. Если вы все еще хотите обработать действие щелчка, когда переключатель отключен, вы можете использовать .setOnTouchListener()...
Лучше всего будет использовать .setOnCheckedChangeListener() и включить включение. В основном, когда вызывается onCheckChanged(), вы можете всплывать в вашем диалоговом окне, если значение ключа включено, и когда пользователь нажимает ok, вы по умолчанию переключитесь на выключение.
mSwitched.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
if (checked && !userInfo.isFilled){
new AlertDialog.Builder(Activity.this)
.setTitle("Fill out info first!")
.setMessage("You must first fill out info before turning on this featurel")
.setNeutralButton("Okay", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
mSwitched.setChecked(false);
}
})
.show();
}
}
});
Вы можете сделать это по-другому. Дайте корневой макет для переключения кнопки с одинаковой шириной и высотой кнопки переключения.
<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"
>
<!--Root layout to toggle button with same height and width
of toggle button-->
<LinearLayout
android:layout_width="wrap_content"
android:id="@+id/linear"
android:layout_height="wrap_content">
<ToggleButton
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
/>
</LinearLayout>
</RelativeLayout>
Если вы отключите кнопку, сделайте эту кнопку нецелесообразной и кликабельной. Затем os передаст функциональность касания к rootlayout. В корневом списке переходов мы можем написать логику щелчка, когда кнопка не включена.
public class MainActivity extends AppCompatActivity {
ToggleButton button;
LinearLayout linearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button= (ToggleButton) findViewById(R.id.button);
linearLayout= (LinearLayout) findViewById(R.id.linear);
//disabling button
button.setEnabled(false);
button.setClickable(false);
button.setFocusableInTouchMode(false);
button.setFocusable(false);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//write the logic here which will execute when button is enabled
}
});
linearLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//write the logic here which will execute when button is disabled
}
});
}
}
Когда вы включаете кнопку, сделайте кнопку кликабельной и фокальной.
//enabling button
button.setEnabled(true);
button.setClickable(true);
button.setFocusableInTouchMode(true);
button.setFocusable(true);