Android NavigationView prevent selecting item, setCheckedItem not working inside onNavigationItemSelected - android

This is the code in onNavigationItemSelected
R.id.nav_subscribed -> {
if (prefs.getLong("userid", 0L) == 0L) {
when (currentGal) {
"top" -> {
// navView.setCheckedItem(R.id.nav_top)
// navView.menu.getItem(R.id.nav_top).isChecked = true
}
}
val i = Intent(this, Login::class.java)
this.startActivity(i)
} else {
if(currentGal != "subscriptions"){
getMemes("subscriptions", 0)
}
}
}
I try to prevent nav_subscribed to be checked when the user isn't logged in and check/keep checked nav_top
navView.setCheckedItem(R.id.nav_top)
isn't working and
navView.menu.getItem(R.id.nav_top).isChecked = true
crashed the app. So how to do this? Btw android is awful broken garbage software

navigationView?.setOnNavigationItemSelectedListener {
when (it.itemId) {
R.id.nav_subscribed -> {
// if you don't want an item to be selected return false
return#setOnNavigationItemSelectedListener false
}
R.id.nav_top -> {
}
}
//return true to select the other items
true
}

Related

Increase value of text when button is hold

I have a plus and min button that work when pressed. Now I want to make them when you hold/press it down it goes up/down more then 1 at a time.
This is one of my regular buttons:
plusBtn.setOnClickListener {
if(isEmpty(PenaltyTimeInputTxt.text))
{
PenaltyTimeInputTxt.setText("0")
}
penaltyInput = PenaltyTimeInputTxt.text.toString().toInt()
if(penaltyInput < 99){
penaltyInput++
PenaltyTimeInputTxt.setText(penaltyInput.toString())
}
else {
Toast.makeText(this, "Penalty time cannot go over 99", Toast.LENGTH_SHORT).show()
}
}
is there a simple way of doing this? I saw something about onTouchListener.
EDIT ---
End result. Thanks to Tenfour04: include the whole fun view.doWhileHeld + this:
plusBtn.doWhileHeld(this.lifecycleScope) {
if(isEmpty(PenaltyTimeInputTxt.text)) {
PenaltyTimeInputTxt.setText("0")
}
penaltyInput = PenaltyTimeInputTxt.text.toString().toInt()
while (isActive) {
if(penaltyInput < 99) {
penaltyInput++
PenaltyTimeInputTxt.setText(penaltyInput.toString())
}
else {
Toast.makeText(this#PenaltyConfigureActivity, "Penalty time cannot go over 99", Toast.LENGTH_SHORT).show()
break
}
delay(200)
}
}
Here is a helper class and function for this, which lets you do whatever you want while the button is held down:
fun View.doWhileHeld(
coroutineScope: CoroutineScope,
block: suspend CoroutineScope.() -> Unit
) = setOnTouchListener(object : View.OnTouchListener {
var job: Job? = null
var pointerInBounds = false
#SuppressLint("ClickableViewAccessibility")
override fun onTouch(view: View, event: MotionEvent): Boolean {
if (!isEnabled) {
job?.cancel()
return false
}
when (event.action) {
MotionEvent.ACTION_DOWN -> {
job = coroutineScope.launch(block = block)
pointerInBounds = true
}
MotionEvent.ACTION_MOVE -> {
val movedInBounds = event.x.roundToInt() in 0..view.width
&& event.y.roundToInt() in 0..view.height
if (pointerInBounds != movedInBounds) {
pointerInBounds = movedInBounds
if (pointerInBounds) {
job = coroutineScope.launch(block = block)
} else {
job?.cancel()
}
}
}
MotionEvent.ACTION_UP -> {
job?.cancel()
}
}
return false // allow click interactions
}
})
It runs a coroutine that restarts every time you click and hold. It also stops the coroutine and restarts it if you drag off the button and then back on, which is a conventional UI behavior.
To use it for your behavior, you can use a while loop:
plusBtn.doWhileHeld(viewLifecycleOwner.lifecycleScope) {
if(isEmpty(PenaltyTimeInputTxt.text)) {
PenaltyTimeInputTxt.setText("0")
}
penaltyInput = PenaltyTimeInputTxt.text.toString().toInt()
while (isActive) {
if(penaltyInput < 99) {
penaltyInput++
PenaltyTimeInputTxt.setText(penaltyInput.toString())
if (penaltyInput == 99) { // optional, might be nicer than showing toast
plusBtn.isEnabled = false
break
}
}
else {
Toast.makeText(this, "Penalty time cannot go over 99", Toast.LENGTH_SHORT).show()
break
}
delay(500) // adjust for how fast to increment the value
}
}
try below code may help
plusBtn.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
// button pressed
object : CountDownTimer(99000, 1000) {
override fun onTick(millisUntilFinished: Long) {
val temp = 99000 - (millisUntilFinished / 1000)
PenaltyTimeInputTxt.setText(""+temp)
}
override fun onFinish() {
Toast.makeText(this, "Penalty time cannot go over 99", Toast.LENGTH_SHORT).show()
}
}.start()
}
if (event.action == MotionEvent.ACTION_UP) {
// button released
}
true
}

Change lambda expression return type to Unit navigation bar

i am very beginner. sorry if its too easy or im stupid. i want to make bottom navigation menu with material design 3 kotlin. but this error comes. i want to change visibility of scroll view. what is problem?
again, im using this: m3.material.io
NavigationBarView.OnItemSelectedListener { item ->
when(item.itemId) {
R.id.main -> {
likes.visibility = View.GONE
mainmenu.visibility = View.VISIBLE
}
R.id.starred -> {
mainmenu.visibility = View.GONE
likes.visibility = View.VISIBLE
}
else -> false
}
}
Going off memory, but I think you missed the word set, as in setOnItemSelectedListener, and the listener needs to return a Boolean for all cases. You only returned it for the else case. Very unlikely you need to worry about returning false (for fall-through behavior), so I'd just return treu after the when statement.
NavigationBarView.setOnItemSelectedListener { item ->
when(item.itemId) {
R.id.main -> {
likes.visibility = View.GONE
mainmenu.visibility = View.VISIBLE
}
R.id.starred -> {
mainmenu.visibility = View.GONE
likes.visibility = View.VISIBLE
}
else -> { }
}
true
}
If you're possibly going to be adding more tabs, I suggest doing your logic like this so it's easier to maintain all the possible cases without having to repeat similar lines of code. The way you're doing it now, you have to write a line of code per tab for each view, and make sure you get the visibility right for each case. You can use the isVisible extension property to hide/show views with Boolean logic.
NavigationBarView.setOnItemSelectedListener { item ->
mainmenu.isVisible = item == R.id.main
likes.isVisible = item == R.id.starred
true
}
I think instead of the onItemSelected, It should be setNavigationItemSelectedListener. I had the same issue with the material top nav bar so, maybe try this out too. Also, try adding log statements and verify if the click statements are working. here's a sample code for reference -
binding.navigationViewMainScreen.setNavigationItemSelectedListener {
Log.d(TAG, "navigationViewMainScreen working")
when (it.itemId) {
R.id.log_in -> {
loginPrompt()
true
}
R.id.log_out -> {
Toast.makeText(requireContext(), "Logged Out", Toast.LENGTH_SHORT)
.show()
CoroutineScope(Dispatchers.IO).launch {
accountDataStore.logOut(requireContext())
}
true
}
R.id.sign_up -> {
findNavController()
.navigate(
MainScreenFragmentDirections.actionMainScreenFragmentToSignUpFragment()
)
true
}
R.id.remove_account -> {
Toast.makeText(requireContext(), "Account Removed", Toast.LENGTH_SHORT)
.show()
CoroutineScope(Dispatchers.IO).launch {
accountDataStore.resetAccounts(requireContext())
}
true
}
R.id.switch_account -> {
switchAccountPrompt()
true
}
R.id.contract_interface -> {
if (userLoggedIn) {
findNavController()
.navigate(
MainScreenFragmentDirections
.actionMainScreenFragmentToContractScreenFragment()
)
} else {
Toast.makeText(
requireContext(), "Log In Necessary To Continue", Toast.LENGTH_SHORT
).show()
loginPrompt()
}
true
}
R.id.about -> {
findNavController()
.navigate(
MainScreenFragmentDirections
.actionMainScreenFragmentToAboutFragment()
)
Log.d(TAG, "about working")
true
}
R.id.exit -> {
Log.d(TAG, "exit working")
logOutAndExit()
true
}
else -> {
throw IllegalArgumentException("side menu item not registered.")
}
}
}
just focus on the content inside. like this one -
R.id.log_in -> {
loginPrompt()
true
}
here we can see an action is performed and it returns true to verify that. Just don't forget the true at the ends. that is used to verify an action has been performed after the button was clicked. Hope it helps.

I want to disable other bottoms after I click once

i am working on QuizApp and I get a problem when I choose an answer and click submit it show me the correct and wrong answer and then I should click submit again to go to the next question, i want to disable that , I want when someone click submit he cant change the answer or choose another answer
here is my code
override fun onClick(v: View?) {
when (v?.id) {
R.id.tv_option_one -> {
selectedOptionView(tv_option_one, 1)
}
R.id.tv_option_two -> {
selectedOptionView(tv_option_two, 2)
}
R.id.tv_option_three -> {
selectedOptionView(tv_option_three, 3)
}
R.id.tv_option_four -> {
selectedOptionView(tv_option_four, 4)
}
R.id.btn_submit -> {
if (mSelectedOptionPosition == 0) {
mCurrentPosition++
when {
mCurrentPosition <= mQuestionsList!!.size -> {
setQuestion()
}
else -> {
// TODO (STEP 5: Now remove the toast message and launch the result screen which we have created and also pass the user name and score details to it.)
// START
val intent =
Intent(this, ResultActivity::class.java)
intent.putExtra(Constants.USER_NAME, mUserName)
intent.putExtra(Constants.CORRECT_ANSWERS, mCorrectAnswers)
intent.putExtra(Constants.TOTAL_QUESTIONS, mQuestionsList!!.size)
startActivity(intent)
finish()
// END
}
}
} else {
val question = mQuestionsList?.get(mCurrentPosition - 1)
// This is to check if the answer is wrong
if (question!!.correctAnswer != mSelectedOptionPosition) {
answerView(mSelectedOptionPosition, R.drawable.wrong_option_border_bg)
//
}
else {
mCorrectAnswers++
}
// This is for correct answer
answerView(question.correctAnswer, R.drawable.correct_option_border_bg)
if (mCurrentPosition == mQuestionsList!!.size) {
btn_submit.text = "FINISH"
} else {
btn_submit.text = "GO TO NEXT QUESTION"
}
mSelectedOptionPosition = 0
}
}
}
}
private fun setQuestion() {
val question = mQuestionsList!!.get(mCurrentPosition - 1) // Getting the question from the list with the help of current position.
defaultOptionsView()
if (mCurrentPosition == mQuestionsList!!.size) {
btn_submit.text = "FINISH"
} else {
btn_submit.text = "SUBMIT"
}
progressBar.progress = mCurrentPosition
tv_progress.text = "$mCurrentPosition" + "/" + progressBar.getMax()
tv_question.text = question.question
iv_image.setImageResource(question.image)
tv_option_one.text = question.optionOne
tv_option_two.text = question.optionTwo
tv_option_three.text = question.optionThree
tv_option_four.text = question.optionFour
}
/**
* A function to set the view of selected option view.
*/
private fun selectedOptionView(tv: TextView, selectedOptionNum: Int) {
defaultOptionsView()
mSelectedOptionPosition = selectedOptionNum
tv.setTextColor(
Color.parseColor("#363A43")
)
tv.setTypeface(tv.typeface, Typeface.BOLD)
tv.background = ContextCompat.getDrawable(
this,
R.drawable.selected_option_border_bg
)
}
/**
* A function to set default options view when the new question is loaded or when the answer is reselected.
*/
private fun defaultOptionsView() {
val options = ArrayList<TextView>()
options.add(0, tv_option_one)
options.add(1, tv_option_two)
options.add(2, tv_option_three)
options.add(3, tv_option_four)
for (option in options) {
option.setTextColor(Color.parseColor("#7A8089"))
option.typeface = Typeface.DEFAULT
option.background = ContextCompat.getDrawable(
this,
R.drawable.default_option_border_bg
)
}
}
/**
* A function for answer view which is used to highlight the answer is wrong or right.
*/
private fun answerView(answer: Int, drawableView: Int) {
when (answer) {
1 -> {
tv_option_one.background = ContextCompat.getDrawable(
this,
drawableView
)
}
2 -> {
tv_option_two.background = ContextCompat.getDrawable(
this,
drawableView
)
}
3 -> {
tv_option_three.background = ContextCompat.getDrawable(
this,
drawableView
)
}
4 -> {
tv_option_four.background = ContextCompat.getDrawable(
this,
drawableView
)
}
}
}
}
in your onclick, change the other views
view.isClickable = false

How to sort reccyclerview in kotlin android

Here I wrote a function where when a particular textView is clicked it will sort the recycler view according to that property but the function only does sorting in descending order. I want functionality where when click the text the first time it sort in ascending order and in the second time it will sort in descending or vice versa. Can please anyone help?
private fun sortTheData(){
binding.statusTextTV.setOnClickListener {
statusAsc = if(statusAsc){
vehicleList.sortedBy {
it.status
}
false
}else{
vehicleList.sortByDescending {
it.status
}
true
}
}
binding.permitTextTV.setOnClickListener {
Log.e(TAG, "sortTheData: $permitAsc", )
permitAsc = if(permitAsc){
vehicleList.sortedBy { vehicle ->
vehicle.permit
}.forEach { println(it.permit) }
false
}else{
vehicleList.sortByDescending { vehicle ->
vehicle.permit
}
true
}
adapter.updateList(vehicleList)
}
binding.licenseTextTV.setOnClickListener {
licenseAsc = if(licenseAsc){
vehicleList.sortedBy {
it.license
}
adapter.updateList(vehicleList)
false
}else{
vehicleList.sortByDescending {
it.license
}
adapter.updateList(vehicleList)
true
}
}
binding.spaceTextTV.setOnClickListener {
spaceAsc = if(spaceAsc){
vehicleList.sortedBy {
it.space
}
vehicleList.forEach{
println(it.space)
}
false
}else{
vehicleList.sortByDescending {
it.space
}
vehicleList.forEach{
println(it.space)}
true
}
}
}
You need to keep a boolean flag and sort accordingly. Pseudo code:
var reversed = false
textView.setOnClickListener {
reversed = !reversed
list = vehicleList.sortedBy { it.license }
if (reversed) {
list = list.reversed()
}
}
You can use type varaible or enum
e.g
var sortType : Int = 1 // 1 or asc & 2 for desc. You can use enum as well
Your sort function will be
fun sort() {
if(sortType == 1) {
sortType = 2
vehicleList.sortByDescending {it.license}
} else {
sortType = 1
vehicleList.sortBy {it.license}
}
adapter.updateList(vehicleList)
}

Double clicking on BottomSheetDialog quickly gives two dialog

I have a bottom sheet dialog fragment that i use as a menu for my bottom app bar.
If i click on the menu icon really quick two times, the dialog shows up two times and i have to close it two times which is annoying.
My code is as follows:
ActivityHome.kt
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
if(mBottomNavDrawerFragment != null && mBottomNavDrawerFragment!!.dialog!!.isShowing){
mBottomNavDrawerFragment?.dismiss()
return false
}
mBottomNavDrawerFragment = RoundedBottomSheetDialogFragment()
mBottomNavDrawerFragment?.show(supportFragmentManager, mBottomNavDrawerFragment?.tag)
true
}
R.id.BottomAppBar_fromHomeActivity_MenuMain_Search -> {
Toast.makeText(this, "Not Implemented yet!", Toast.LENGTH_SHORT).show()
false
}
else -> true
}
}
Can anyone help? Thanks
Show the dialogFragment using a tag. Check if the tag exists in the stack before showing it again
if(getChildFragmentManager().findFragmentByTag(FragmentDialog.TAG) == null) {
fragmentDialog.show(getChildFragmentManager(), FragmentDialog.TAG);
}
You can do a little bit hack here. Here is the code.
private var saveClickCounter = 0
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
return when (item?.itemId) {
R.id.home -> {
if (saveClickCounter++ == 0) {
//Your Dialog Showing Code
Handler().postDelayed({
saveClickCounter=0
},1000)
}
true
}
R.id.BottomAppBar_fromHomeActivity_MenuMain_Search -> {
Toast.makeText(this, "Not Implemented yet!", Toast.LENGTH_SHORT).show()
false
}
else -> true
}
}
Make a variable saveClickCounter to store your counts.
On clicks increase the value of saveClickCounter and change it to zero after N seconds of delayed. I used 1 second in below code.

Categories

Resources