Toggle and untoggle a DropdownMenu's appearance - android-jetpack-compose

I have an Icon . And when the Icon is clicked it toggles the expanded state variable. The expanded state variable toggles a DropdownMenu. And that DropdownMenu appears underneath the Icon.
DropdownMenu has a onDismissRequest callback. onDismissRequest runs when the user clicks outside the DropdownMenu. onDismissRequest toggles the expanded state variable, and so closes the DropdownMenu.
However, if the user clicks outside DropdownMenu, and specifically on the icon, onDismissRequest sets expanded to false. But the user has also clicked on the Icon. And the Icon sets expanded to true.
And so, clicking on the icon again does not close the DropdownMenu: it opens it.
#Composable
fun MyComponent() {
var expanded by remember { mutableStateOf(false) }
Column() {
Icon(Icons.Filled.Menu, "",
Modifier.clickable { expanded = !expanded }
)
DropdownMenu(expanded, { expanded = false }) {
DropdownMenuItem({ }) {
Text("Menu item")
}
}
}
}
So, how can I toggle and untoggle a DropdownMenu's appearance?
If I could make onDismissRequest swallow all the interactions I could prevent my Icon's click listener opening the menu again--but I'm not sure that's possible.

You can disable clickable when it's not expanded:
.clickable(enabled = !expand)

Make the clicking on the icon only opening the dropdown menu, instead of toggling it:
Icon(Icons.Filled.Menu, "",
Modifier.clickable { expand = true }
)
Also, make clicking on any of the dropdown menu items to close the menu:
DropdownMenuItem(onClick = { expand = false})
That way, clicking the icon will only expand the dropdown, and clicking on any dropdown item or anywhere else will close it.

Related

Change highlight on clickable Text possible?

I have a #Composable Text("Dropbox") whose Modifier also implements a
clickable {
//..
}
But when I tapping on it
, it gets a grey highlight!?
I do not want this grey hightlight. Can I get rid of this?
Here indication is responsible for showing the highlight.
So making indication = null should do the job
.clickable(
onClick = {
//..
},
indication = null,
interactionSource = remember { MutableInteractionSource() }
)

Jetpack navigation compose, bottom nav, make back button switch tabs?

I'm trying to use bottom navigation (ie, tabs) with Android Jetpack Compose and the Navigation Compose library. I have it set up with multiple back stacks, so that the state of each tab is preserved when you switch between them. However, if I change tabs by tapping one of them, the Android back button does not go back to the previous tab. Instead it navigates within that tab. How do I set it up to go back to previous tab?
Example scenario (I want to change behavior of last step).
I have two tabs, A and B.
Start in the A tab, on screen A1.
Push a new screen in that tab, called A2.
Tap the B tab to move to it, on its start screen B1.
Push a new screen in that tab, B2. So the tab stacks are now: A:[A1,A2], and B:[B1, B2]
Tap the A tab. I'm back in that stack, on screen A2. The state in that tab was preserved.
Press Android back button. It goes to A1. Instead I want it to go back to the B tab, screen B2.
MyAppBottomNavItem.all.forEach { item ->
BottomNavigationItem(
icon = { Icon(item.icon, contentDescription = null) },
label = {
Text(item.name, maxLines = 1, textAlign = TextAlign.Center,
overflow = TextOverflow.Visible, softWrap = false,
fontSize = 10.sp)
},
selected = currentDestination?.hierarchy?.any { it.route == item.route } == true,
alwaysShowLabel = true,
onClick = {
nav.navigate(item.route) {
popUpTo(nav.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}

Cannot turn autoCorrect to {false} in react native TextInput

On my TextInput change text, I detect whether the user pushed the # button for mentions.
onChangeText(text){
const suggestTrigger = text.match(/\B#[A-Za-z0-9]*$/i) //grab "#" trigger
const searchQuery = (suggestTrigger && suggestTrigger.length > 0) ? suggestTrigger[0] : null;
this.setState({
searchQuery: searchQuery
})
}
Then, in my render, I do:
<TextInput
autoCapitalize={this.state.searchQuery ? "none" : "sentences"}
autoCorrect={this.state.searchQuery ? false : true}
onChangeText={this.onChangeText}
/>
However, even when I do this, the autoCorrect does not turn off.
I still see this:
This is causing problems because oftentimes the system replaces the entire mention with a different word altogether.
How can I turn autoCorrect and autoCapitalize off when the user pushes the # button?
'
I have even tried rendering an entirely different , but the behavior remains.
TL;DR: you should close and re-launch your keyboard after the TextInput autoCorrect toggling value.
Buddy, this is not your fault, I had the same issue on autoFocus of react native TextInput component. I set a state name for the TextInput editable prop and then with the pressing pencil button I change the editable props. The designer told me after the TextInput made editable the cursor should be focused, so I use the isEditable state for autoFocus prop, see below:
state = {
isEditable: false
};
handleEdit = () => {
const { isEditable } = this.state;
this.setState({ isEditable: !isEditable });
};
<TextInput
autoFocus={isEditable}
editable={isEditable}
style={styles.textNameEditable}
defaultValue={text}
numberOfLines={1}
/>
Then I press the edit button and it turns to:
But it is not focused and the Keyboard didn't launch, I sought and found this link, the TextInput does not change/update some of its props after componentDidMount. ☹️. Also, it is not different in iOS or Android, both of them has this issue, I used ref to focus on this TextInput after the isEditable state made true. see following code:
<TextInput
editable={isEditable}
style={styles.textNameEditable}
defaultValue={text}
numberOfLines={1}
ref={input => {
this.input = input;
}}
/>
componentDidUpdate() {
const { isEditable } = this.state;
if (isEditable) {
this.input.focus();
}
}
And your case:
Absolutely you can not use ref because the autoCorrect should render with react native and it is not like focus() and blur() so JavaScript cannot access to it.
I make a test shape for your case, I create another button like a star for toggling autoCorrect value alongside my edit button. the filled star means autoCorrect is true and the lined star means autoCorrect is false, now see the test area code and view:
state = {
isEditable: false,
correct: true
};
handleCorrect = () => {
const { correct } = this.state;
this.setState({ correct: !correct });
};
<TextInput
autoCorrect={correct}
editable={isEditable}
style={styles.textNameEditable}
defaultValue={text}
numberOfLines={1}
ref={input => {
this.input = input;
}}
/>
In the above photo, it is so clear the autoCorrect rendered as true, so it is enabled:
When I write a wrong Persian word the auto-correction show its suggestion, now time to press the star button:
Wow, the autoCorrection is false in the above situation but still we see the auto-correction of the cellphone. it is just like autoFocus it is rendered in the first render and after it, the TextInput could not change/update its props. suddenly I press edit button:
And I press the edit button again, so surely, you realized the autoCorrect is false now, ok now see what I saw:
The autoCorrect remained false by my double pressing edit button and now the auto-correction of device disappears completely. I don't know it is a bug or my bad understanding but I realized in this test area, for update autoCorrect value, we should do something after changing its value to close the iPhone keyboard and then re-launch it. the main thing that TextInput has issued is the launched keyboard.
For my test, when I pressed the edit button the editable prop of the TextInput is changed to false and the keyboard is closed, so when I pressed the edit button again, the TextInput get focused and keyboard re-launched with new autoCorrect value. This is The Secret.
Solution:
You should do something, to close and open again the iOS keyboard with the new autoCorrect value. for the test case that I wrote for your question, I decided to do a hybrid innovative solution, using ref and the callback of setState:
handleCorrect = () => {
const { correct } = this.state;
this.input.blur(); //-- this line close the keyboard
this.setState({ correct: !correct },
() => {
setTimeout(() => this.input.focus(), 50);
//-- above line re-launch keyboard after 50 milliseconds
//-- this 50 milliseconds is for waiting to closing keyborad finish
}
);
};
<TextInput
autoCorrect={correct}
editable={isEditable}
style={styles.textNameEditable}
defaultValue={text}
numberOfLines={1}
ref={input => {
this.input = input;
}}
/>
And after pressing the star button the keyboard close and re-launch and the auto-correction disappear completely.
Note: obviously, I summarized some other codes like destructuring and writing class or extends and etc for better human readability.
The problem isn't in your code completely(except Regex part which didn't work in my device) but how the React Native renders Keyboard.
I created a sample that along with your initial code also changes backgroundColor of the screen.
You will find that color changes instantly when '#' is entered whereas the keyboard doesn't.
Unless you reload the keyboard. For this, if you un-comment the code it dismisses keyboard once and once you tap back on textInput the new Keyboard without autoCorrect and autoCapitalize is shown.
state = {
searchQuery: null,
isFocused: true,
}
constructor(props) {
super(props);
this.onChangeText = this.onChangeText.bind(this);
}
onChangeText = (val) => {
const suggestTrigger = val.match(/#[A-Za-z0-9]*$/i) //grab "#" trigger
const searchQuery = (suggestTrigger && suggestTrigger.length > 0) ? suggestTrigger[0] : null;
// Un comment this to reload
// if(searchQuery && this.state.isFocused) {
// this.setState({
// isFocused: false
// });
// Keyboard.dismiss();
// // this.myTextInput.focus()
// }
this.setState({
searchQuery: searchQuery
})
}
render() {
const { searchQuery } = this.state
return (
<View style={[styles.container,
{
backgroundColor: searchQuery ? "red": "green"}
]}>
<TextInput
style={{width: 300, height: 50, borderWidth: 1}}
ref={(ref)=>{this.myTextInput = ref}}
autoCapitalize={searchQuery ? "none" : "sentences"}
autoCorrect={searchQuery ? false : true}
onChangeText={this.onChangeText}
/>
</View>
);
}
Since now we know the main cause of error may be a better solution can be reached.
I have 2 suggestions:
First, have you tried using the autoCorrect fallback?
spellCheck={this.state.searchQuery ? false : true}
Second, have you tried with native code (Obj-C / Swift)?
import { Platform, TextInput, View } from 'react-native';
import { iOSAutoCorrect } from './your-native-code';
const shouldWork = Platform.OS === 'ios' ? <iOSAutoCorrect /> : <TextInput
autoCapitalize={this.state.searchQuery ? "none" : "sentences"}
autoCorrect={this.state.searchQuery ? false : true}
onChangeText={this.onChangeText} />
return (<View>{shouldWork}</View>);
In iOSAutoCorrect you should use a UITextView. Then set its proper value depending on your condition:
textField.autocorrectionType = UITextAutocorrectionTypeNo; // or UITextAutocorrectionTypeYes
I have free-coded, thus the code is untested and might contain bugs.

Swift: UITextfield affecting button click? Unable to enter text due to animation?

I am having an odd problem with my UIView animations and a UITextfield - I need to be able to click a button, have the button animate up to reveal a textfield so the user can enter text in the text field, then when the user presses that button again user interaction is disabled on the text field and the button moves back over.
This is what I mean-
I have accomplished this to an extent by placing the textfield behind the button and disabling it at the start, then when the button is clicked the button animates up to reveal the text field, which becomes enabled:
Problem is that the button click is being triggered (or possibly just the animation) when the user goes to edit the text field. So when they go to type, the button just moves back down and covers the text field.
This is odd because I have a boolean to set whether the button moves up or down, and I do not think this is being flipped because often the button moves BELOW the textfield, which should never happen.
Here is how I'm doing this:
#IBAction func enterText(sender: UIButton) {
print("time to enter text")
if !textOpen
{
UIView.animateWithDuration(0.5, animations: {
self.textBtn.center.y -= self.textBtn.bounds.height
})
happenedTxt.userInteractionEnabled = true
}
else {
UIView.animateWithDuration(0.5, animations: {
self.textBtn.center.y += self.textBtn.bounds.height
})
happenedTxt.userInteractionEnabled = false
}
textOpen = !textOpen
}
How can I trigger the button move ONLY when the button is pressed? Why is the textfield triggering the animation? Is there some call being made to return the button to its original position?

jquery ui drag element without keeping mouse button down (follow the cursor)

I am trying to drag an element without keeping the mouse button down.
The behavior I would like is :
I click on a draggable item
Drag my item without keeping mouse left click down : just follow the mouse as a cursor
I click on a droppable container to confirm and append my item
I am able to simulate this behavior if I add an alert box durring the start event.
start : function(){
alert('test')
},
Here is the fiddle : http://jsfiddle.net/QvRjL/103/
How is it possible to code this behavior without the alert box?
Here is a good solution about this problem : Trigger Click-and-Hold Event
http://jsfiddle.net/VXbpu/1/
http://jsfiddle.net/vPruR/70/
var click = false;
$(document).bind('mousemove', function (e) {
if (click == true) {
$('#your_div_id').css({
left: e.pageX,
top: e.pageY
});
}
});
$('#your_div_id').click(function() {
click = !click;
return false;
});
$('html').click(function() {
click = false;
});

Resources