如何仅在特定条件下实现自定义 BackHandler 行为?
How to achieve custom BackHandler behavior only under a certain condition?
我的应用程序中有一个平面列表,我想让用户在长按时将特定列表项标记为已选中,并提供一个删除按钮以一次性删除多个项目。这些是我期望的行为。
- 如果没有选择平面列表中的任何项目,按一个项目会打开一个包含项目详细信息的新屏幕,然后按“后退”按钮可返回平面列表。
- 如果没有选择任何项目,长按一个项目会将其标记为已选择。选择任何特定项目后按下的每个项目都被标记为已选择,而不是打开详细信息屏幕。
- 已经选中然后按下的项目变为未选中。
- 如果选择了任意数量的项目,将呈现一个删除按钮并且按下后退按钮取消选择所有项目。
我已经能够实现前三个行为中的大部分,但我完全迷失了 Back Handler。这是我的组件,为了简洁起见,只有相关代码。仅显示包含选择删除的项目的状态数组和用作平面列表的 RenderItem 道具的 listItem。
const Home = (props) => {
const [deleteItems, setDeleteItems] = useState([]);
const renderItem = ({ item }) => {
let bb_OR_ub = item.useBy ? 'Use By ' : 'Best Before '
let exp_check = CheckExp(item, 1);
let listStyle = {};
if (exp_check === -1)
listStyle = { backgroundColor: '#ff9ea5' }
else if (exp_check === 0)
listStyle = { backgroundColor: '#fff185' }
if (deleteItems.indexOf(item.name) != -1) {
listStyle = { opacity: 0.3 }
}
return (
<ListItem
containerStyle={listStyle}
badge={
exp_check !== 1 ?
exp_check === -1 ? { status: 'error', value: `!` } : {
status: 'warning'
} : null
}
title={item.name}
subtitle={bb_OR_ub + item.date}
bottomDivider
leftAvatar={{ source: require('../shared/cexp.png'), imageProps: { resizeMode: 'contain' } }}
onPress={() => {
if (deleteItems.length == 0)
navigate('ExpiryDetails', { item })
else {
setDeleteItems([...deleteItems, item.name])
}
}}
onLongPress={() => {
if (deleteItems.indexOf(item.name) == -1 || deleteItems.length == 0) {
setDeleteItems([...deleteItems, item.name])
}
else {
setDeleteItems(deleteItems.filter(el => el != item.name))
}
}} />
);
}
react-native 提供的 BackHandler
允许您订阅按下后退按钮。提供给后处理程序的回调可以提供 true
(当不应触发默认行为时)或 false
(当允许默认行为继续时)。
对于您的情况,我们希望在选择项目时在背面有自定义行为,此时我们希望取消选择所有项目。
我调整了您的代码以引入 BackHandler
并取消选择背面被按下的任何项目
const Home = (props) => {
const [deleteItems, setDeleteItems] = useState([]);
// Subscribe to BackHandler once the component is mounted
// or when deletedItems changes
useEffect(() => {
const handler = BackHandler.addEventListener('hardwareBackPress', () => {
// If no deleted items: we return false
if (!deletedItems.length) {
return false;
}
// clear the selected items, and indicate that the back if handled
setDeletedItems([]);
return true;
});
// unsubscribe when component unmounts
return () => {
handler.remove();
};
}, [deletedItems]);
const renderItem = ({ item }) => {
let bb_OR_ub = item.useBy ? 'Use By ' : 'Best Before '
let exp_check = CheckExp(item, 1);
let listStyle = {};
if (exp_check === -1)
listStyle = { backgroundColor: '#ff9ea5' }
else if (exp_check === 0)
listStyle = { backgroundColor: '#fff185' }
if (deleteItems.indexOf(item.name) != -1) {
listStyle = { opacity: 0.3 }
}
return (
<ListItem
containerStyle={listStyle}
badge={
exp_check !== 1 ?
exp_check === -1 ? { status: 'error', value: `!` } : {
status: 'warning'
} : null
}
title={item.name}
subtitle={bb_OR_ub + item.date}
bottomDivider
leftAvatar={{ source: require('../shared/cexp.png'), imageProps: { resizeMode: 'contain' } }}
onPress={() => {
if (deleteItems.length == 0)
navigate('ExpiryDetails', { item })
else {
setDeleteItems([...deleteItems, item.name])
}
}}
onLongPress={() => {
if (deleteItems.indexOf(item.name) == -1 || deleteItems.length == 0) {
setDeleteItems([...deleteItems, item.name])
}
else {
setDeleteItems(deleteItems.filter(el => el != item.name))
}
}} />
);
}
我的应用程序中有一个平面列表,我想让用户在长按时将特定列表项标记为已选中,并提供一个删除按钮以一次性删除多个项目。这些是我期望的行为。
- 如果没有选择平面列表中的任何项目,按一个项目会打开一个包含项目详细信息的新屏幕,然后按“后退”按钮可返回平面列表。
- 如果没有选择任何项目,长按一个项目会将其标记为已选择。选择任何特定项目后按下的每个项目都被标记为已选择,而不是打开详细信息屏幕。
- 已经选中然后按下的项目变为未选中。
- 如果选择了任意数量的项目,将呈现一个删除按钮并且按下后退按钮取消选择所有项目。
我已经能够实现前三个行为中的大部分,但我完全迷失了 Back Handler。这是我的组件,为了简洁起见,只有相关代码。仅显示包含选择删除的项目的状态数组和用作平面列表的 RenderItem 道具的 listItem。
const Home = (props) => {
const [deleteItems, setDeleteItems] = useState([]);
const renderItem = ({ item }) => {
let bb_OR_ub = item.useBy ? 'Use By ' : 'Best Before '
let exp_check = CheckExp(item, 1);
let listStyle = {};
if (exp_check === -1)
listStyle = { backgroundColor: '#ff9ea5' }
else if (exp_check === 0)
listStyle = { backgroundColor: '#fff185' }
if (deleteItems.indexOf(item.name) != -1) {
listStyle = { opacity: 0.3 }
}
return (
<ListItem
containerStyle={listStyle}
badge={
exp_check !== 1 ?
exp_check === -1 ? { status: 'error', value: `!` } : {
status: 'warning'
} : null
}
title={item.name}
subtitle={bb_OR_ub + item.date}
bottomDivider
leftAvatar={{ source: require('../shared/cexp.png'), imageProps: { resizeMode: 'contain' } }}
onPress={() => {
if (deleteItems.length == 0)
navigate('ExpiryDetails', { item })
else {
setDeleteItems([...deleteItems, item.name])
}
}}
onLongPress={() => {
if (deleteItems.indexOf(item.name) == -1 || deleteItems.length == 0) {
setDeleteItems([...deleteItems, item.name])
}
else {
setDeleteItems(deleteItems.filter(el => el != item.name))
}
}} />
);
}
react-native 提供的 BackHandler
允许您订阅按下后退按钮。提供给后处理程序的回调可以提供 true
(当不应触发默认行为时)或 false
(当允许默认行为继续时)。
对于您的情况,我们希望在选择项目时在背面有自定义行为,此时我们希望取消选择所有项目。
我调整了您的代码以引入 BackHandler
并取消选择背面被按下的任何项目
const Home = (props) => {
const [deleteItems, setDeleteItems] = useState([]);
// Subscribe to BackHandler once the component is mounted
// or when deletedItems changes
useEffect(() => {
const handler = BackHandler.addEventListener('hardwareBackPress', () => {
// If no deleted items: we return false
if (!deletedItems.length) {
return false;
}
// clear the selected items, and indicate that the back if handled
setDeletedItems([]);
return true;
});
// unsubscribe when component unmounts
return () => {
handler.remove();
};
}, [deletedItems]);
const renderItem = ({ item }) => {
let bb_OR_ub = item.useBy ? 'Use By ' : 'Best Before '
let exp_check = CheckExp(item, 1);
let listStyle = {};
if (exp_check === -1)
listStyle = { backgroundColor: '#ff9ea5' }
else if (exp_check === 0)
listStyle = { backgroundColor: '#fff185' }
if (deleteItems.indexOf(item.name) != -1) {
listStyle = { opacity: 0.3 }
}
return (
<ListItem
containerStyle={listStyle}
badge={
exp_check !== 1 ?
exp_check === -1 ? { status: 'error', value: `!` } : {
status: 'warning'
} : null
}
title={item.name}
subtitle={bb_OR_ub + item.date}
bottomDivider
leftAvatar={{ source: require('../shared/cexp.png'), imageProps: { resizeMode: 'contain' } }}
onPress={() => {
if (deleteItems.length == 0)
navigate('ExpiryDetails', { item })
else {
setDeleteItems([...deleteItems, item.name])
}
}}
onLongPress={() => {
if (deleteItems.indexOf(item.name) == -1 || deleteItems.length == 0) {
setDeleteItems([...deleteItems, item.name])
}
else {
setDeleteItems(deleteItems.filter(el => el != item.name))
}
}} />
);
}