android - 在 inflated layout 中的 Switch View 上设置的 OnCheckedChangeListener 不会触发

标签 android xml android-layout listview layout-inflater

我正在学习 Android 开发,我打算在 ListView 中显示任何已连接/配对的蓝牙设备。每个列表项在左侧都有一个设备名称,在右侧有一个开关。 截图有点大

ConnectedDevicesActivity visual end result

我设计了每个项目如何在单独的 bluetooth_device_entry.xml 文件中显示。

bluetooth_device_entry.xml 文件使用 RelativeLayout 进行布局,它有两个子元素 TextViewSwitch

在主布局 XML 文件 activity_connected_devices.xml 中,我有一个 ListView,我用 bluetooth_device_entry.xml 文件以编程方式填充它。

我的问题出在 Java Activity ConnectedDevicesActivity.java 中。我能够将 setOnItemClickListener 附加到 ListView 项目,但即使在 bluetooth_device_entry.xml 膨胀之后 setOnChangeListener() 附加到膨胀的布局开关没有被触发。

bluetoothConnectedDeviceItemClickListener 有效,但 switchCheckedListener 无效。

知道如何解决这个问题吗?谢谢。

bluetooth_device_entry.xml

(用什么填充每个 ListView 项)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/bluetoothDeviceEntryLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:descendantFocusability="blocksDescendants">

    <TextView
        android:id="@+id/connectedDeviceName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/light_grey"

        android:paddingBottom="12dp"
        android:paddingEnd="8dp"
        android:paddingStart="8dp"
        android:paddingTop="12dp"
        android:text="@string/txtPlaceHolderConnectedBluetoothText"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textSize="@dimen/dimen_listTextSizeMedium" />

    <Switch
        android:id="@+id/deviceStateSwitch"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_alignBaseline="@+id/connectedDeviceName"
        android:layout_alignBottom="@+id/connectedDeviceName"
        android:layout_alignParentEnd="true"
        android:layout_marginEnd="15dp"
        android:switchMinWidth="@dimen/dimen_switchWidth" />

</RelativeLayout>

activity_connected_devices.xml

(Activity 最初由 onCreate() 中的 ConnectedDevicesActivity.java 加载)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activityConnectedDevicesLinearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/txtTitleConnectedDevices"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="@color/dark_blue"
        android:gravity="center"
        android:text="@string/txtConnectedDevices"
        android:textColor="@color/light_blue"
        android:textSize="@dimen/dimen_buttonTextSize" />

    <ListView
        android:id="@+id/bluetoothConnectedDevicesListView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="3" />
</LinearLayout>

ConnectedDevicesActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.Switch;
import android.widget.Toast;

public class ConnectedDevicesActivity extends AppCompatActivity
{
    ListView bluetoothConnectedDevicesListView;
    Switch deviceSwitch;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_connected_devices);
        setTitle("Connected Devices");

        bluetoothConnectedDevicesListView = findViewById(R.id.bluetoothConnectedDevicesListView);

        showConnectedBluetoothDevices();
    }

    public void showConnectedBluetoothDevices()
    {
        String[] connectedBluetoothDevices = new String[10];
        for(int i=0; i<connectedBluetoothDevices.length; i++)
        {
            connectedBluetoothDevices[i] = "Device " + (i+1);
        }


        ArrayAdapter<String> connectedBluetoothDevicesAdapter =
                new ArrayAdapter<String>(this,
                        R.layout.bluetooth_connected_devices_entry,
                        R.id.connectedDeviceName,
                        connectedBluetoothDevices);

        bluetoothConnectedDevicesListView.setAdapter(connectedBluetoothDevicesAdapter);
        bluetoothConnectedDevicesListView.setOnItemClickListener(new bluetoothConnectedDeviceItemClickListener());

        View inflatedView = getLayoutInflater().inflate(R.layout.bluetooth_connected_devices_entry, null);
        deviceSwitch = inflatedView.findViewById(R.id.deviceStateSwitch);

        /* This is not responding to switch loaded from inflated view */
        deviceSwitch.setOnCheckedChangeListener(new switchCheckedListener());

        Toast.makeText(
                ConnectedDevicesActivity.this,
                String.format("Switch checked? %b", deviceSwitch.isChecked()),
                Toast.LENGTH_SHORT).show();
    }

    public class bluetoothConnectedDeviceItemClickListener implements OnItemClickListener
    {
        /* When the user taps an item in the list view */
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id)
        {
            Toast.makeText(
                    ConnectedDevicesActivity.this,
                    String.format("You tapped %s", bluetoothConnectedDevicesListView.getItemAtPosition(position)),
                    Toast.LENGTH_SHORT).show();
        }
    }
    /* When the user toggles a switch */
    public class switchCheckedListener implements CompoundButton.OnCheckedChangeListener
    {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
        {
            Toast.makeText(
                    ConnectedDevicesActivity.this,
                    String.format("Checked state is %s", isChecked),
                    Toast.LENGTH_SHORT).show();
        }
    }
}

最佳答案

您正在膨胀一个与您的 ListView 的项目无关的额外 View

 bluetoothConnectedDevicesListView.setAdapter(connectedBluetoothDevicesAdapter);
 bluetoothConnectedDevicesListView.setOnItemClickListener(new bluetoothConnectedDeviceItemClickListener());

 View inflatedView = getLayoutInflater().inflate(R.layout.bluetooth_connected_devices_entry, null);
 // ^^^^^^^^ totally a new item, has no relation with views inside list
 deviceSwitch = inflatedView.findViewById(R.id.deviceStateSwitch);

 deviceSwitch.setOnCheckedChangeListener(new switchCheckedListener());

解决方案:You need to create a customize Adapter它将负责提供每个单独的 rowitem View ,并且在 getView 中,您可以对 rowitem View 中的 subview 应用操作(附加监听器/操作值)。

注意:您还需要管理一个列表来跟踪切换 View 状态,因为适配器会重新创建|重用 View 。

关于android - 在 inflated layout 中的 Switch View 上设置的 OnCheckedChangeListener 不会触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47252242/

相关文章:

xml - 在 styles.xml 中设置特定字体

Android屏幕捕获或从图像制作视频

java - 仅通过 XML(无需其他可绘制对象)单击时如何更改按钮的颜色?

c# - XML 属性中的 JSON

android - Imageview 中的模糊图像问题

python - 在属性 ID 相同的地方合并 XML 文件 Python

java - 如何在我的 TextView 中以粗体和多色显示文本

android - 忽略 layout_gravity 的自定义 Actionbar 选项卡 View

android - 自定义ExpandableListView时默认箭头继续出现

java - Android MapView方向箭头