I have a seekbar that goes from 0-12, but I'd like to make it not possible to select one of the values based on some other criteria. Is that possible? i.e. they can slide through 0-12 but it skips 5? Is there a better selection method maybe? I like how minimal the seekbar is to perform this function, but open to other ideas, if removing a selection is not an option.
Easy way to do it
bar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
var previousProgress = 0
val disabled = intArrayOf(3,5,7)
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if (disabled.contains(progress)) seekBar?.progress = previousProgress
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
previousProgress = seekBar?.progress ?: 0
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
Related
I have a search bar, after searching in the search bar, if I click back button the app closes. What I want is if I click back button after searching in search bar the default list must be shown.
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if(){
}else{
isEnabled = false
activity?.onBackPressed()
}
}
})
searchBar.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
val listData = arrayListOf<Restaurant>()
for (i in 0 until restaurantInfoList.size) {
if (restaurantInfoList[i].restaurantName.toLowerCase()
.contains(searchBar.text.toString().toLowerCase()) ||
restaurantInfoList[i].restaurantPrice.contains(searchBar.text.toString()) ||
restaurantInfoList[i].restaurantRating.contains(searchBar.text.toString())
) {
listData.add(restaurantInfoList[i])
}
}
recyclerDashboard.adapter = RestaurantRecycleAdapter(activity as Context, listData)
(recyclerDashboard.adapter as RestaurantRecycleAdapter).notifyDataSetChanged()
}
}
)
The app is closing because you have called the activity's onbackPressed() method. Unless you handle the callback on your own, it will close.
In your backpressed method, check if your search bar is empty and produce the default list in the adapter.
Remove this line in else condition
activity?.onBackPressed()
I am trying to make it so that a progress bar that I put in my edittext field will spin after the user has typed in text. The progress bar should continue to spin until the user has not typed in any more text for one second. (If the user keeps typing in text, the progress bar should keep spinning.) I am using a textWatcher:
et_username_username.addTextChangedListener(object: TextWatcher {
override fun afterTextChanged(p0: Editable?) {}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
pb_username_progress_bar.visibility = View.VISIBLE
val updatedText = p0.toString().trim().toLowerCase()
CoroutineScope(IO).launch{
delay(1000)
pb_username_progress_bar.visibitlity = View.INVISIBLE
//updates UI based on firebase database code
}
}
})
However, when I run this, the coroutine just runs on a different thread every time so the progress bar goes away when the user keeps typing for over a second.
How do I make it so that the progress bar will stay there when the user keeps typing, are coroutines the best way or is there another way??
(It should look a lot like instagram when you create a new account, how it has the spinning progress bar when making username)
You can use following code snippet as solution. It will solve your problem.
edit_search.addTextChangedListener(object : TextWatcher {
private var searchFor = ""
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
val searchText = s.toString().trim()
if (searchText == searchFor)
return
searchFor = searchText
progress_bar.visibility = View.VISIBLE
CoroutineScope(IO).launch {
delay(1000)
if (searchText != searchFor)
return#launch
progress_bar.visibility = View.INVISIBLE
}
}
})
Happy Coding :)
I have a discrete SeekBar that can take a value from 0 to 10. But I want to let the user select values from 1 to 9 only. How can I achieve this?
You can programatically set max limit of seekbar after the user has given desired range like this:
seekbar.setMax(userInput);
To resolve this issue I've implemented custom OnSeekBarChangeListener:
binding.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
when(progressValue) {
0 -> seekBar.progress = 1
10 -> seekBar.progress = 9
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
I am try to implement seekBar1.setOnSeekBarChangeListener()
In Java, I just write new keyword and auto-complete help me implementation and know which interface I have to Implement
is there any way like this in kotlin
or I have to remember all of these Interfaces
I know there is no new keyword in kotlin , but I asked about how after I write object auto complete take place
The shortcut you are looking for is Ctrl + Shift + Space
In kotlin, use "object" keyword to implement an interface.
seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
There is no key word new in kotlin, just don't use it .
You have to use object : to override anonymous inner classes
seekBar.setOnSeekBarChangeListener(object :SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
See Docs https://kotlinlang.org/docs/reference/object-declarations.html
Use object to implement an interface.
// Set a SeekBar change listener
seek_bar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
// Do something
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
// Do something
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
// Do something
}
})
Kotlin doesn't contain new keyword. So yes, according to your dilemma it's pain is the neck. But it does provide you auto-complete!
All you've to do is make object of particular interface and then it generates you error about not implementing methods from that & then by using command Alt+Enter you can implement all methods from that interface.
In your case just type:
seekBar1.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {})
Which will show you compilation error at object keyword.
If your interface is having single method implementation, you can directly use Sam-constructor implementation. I.e. for click listeners in Kotlin provides you direct autocomplete from suggestions something like :
view.setOnClickListener {
//This is the same click listener we used to implement in our Java code
}
after writed your object listener, for example;
(object:ApiCallback<JSONObject>{})
and put your cursor to above object, you'll see import method after make option+enter combination
(option+enter shurtcut valid for macbook keyboard, if you use windows u have to find another solution that have show listener implementation methods.
I have a custom adapter, and filter that I am currently implementing to filter a recycler view based on a simple substring search on my recycler view entries. Here is my adapter NotifyChanged() function, which updates the RecylerView, and my custom filter() function. Everything works great, except for the auto scrolling afterwards.
private fun notifyChanged() {
val result = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return objects.size
}
override fun getNewListSize(): Int {
return temp.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return this#DiffRecyclerViewAdapter.areItemsTheSame(objects[oldItemPosition], temp[newItemPosition])
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return this#DiffRecyclerViewAdapter.areContentsTheSame(objects[oldItemPosition], temp[newItemPosition])
}
})
objects.clear()
objects.addAll(temp)
result.dispatchUpdatesTo(this)
}
fun filter(text : String){
val ob = original_objects as ArrayList<Category>
val filtered_categories = ArrayList<T>() as ArrayList<Category>
for (category in ob){
//val temp_category = category
val list_of_subcategories = ArrayList<T>() as ArrayList<Category>
for (subcategory in category.categories){
val name_of_category = subcategory.name.toLowerCase()
if (name_of_category.contains(text)){
list_of_subcategories?.add(subcategory)
}
}
if (list_of_subcategories.size > 0){
val newCategory = Category(category.id,category.name,category.description,category.videos,list_of_subcategories)
filtered_categories.add(newCategory)
}
}
temp = filtered_categories as MutableList<T>
notifyChanged()
}
In my SearchActivity.kt I have the following listener:
searchEditText.addTextChangedListener(object : TextWatcher{
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
adapter.filter(s.toString())
recyclerView.scrollToPosition(0)
}
})
I was looking through the source code of DiffUtil and notifyDataSetChanged() to see how scrolling after filtering works. But didn't have much luck. The whole problem is that after I search text the RecyclerView is filtered fine. But will scroll to inconsistent locations. I want it to scroll back to the top every single time, but this isn't happening. EVEN WITH scrollToPosition(0) it will USUALLY scroll to the top, but not always.
I thought scrolling to the top was typically automatic in this case. I'm curious as to what the best practice is in updating and scrolling.
It needs some time to update the data on recyclerview. Mean while you are trying to scroll which doesn't work in most of the cases. PReferably use a postDelayed with 200 or 300 milliseconds before scrolling
Ex:
new Handler.postDelayed(new Runnable(){
#Override
public void run(){
recyclerView.scrollToPosition(0)
}
}, 300);