Using a SeekBar within a ListView - android

I have a seekbar in a listview, it is disabled to stop the user from changing the value whilst scrolling the list. I wish to enable it if the list item is long clicked, allow the user to change it and then disable it again.
Any suggestions.
I seem unable to access the seekbar from the activity as it is setup inside the ArrayAdapter to display a value from the database
I am able to fire a both a click event and a long click event for the list item, as the seekbar is currently disabled.

Solution
In the ArrayAdapter I set both enabled and focusable to false and added the SeekBar listener, setting the attributes to false allowed me to use the list item onItemClicked listener. Inside the onItemCLickListener I retreived the seekbar, set the attributes to true, this meant it could be slid up or down. I then disabled it after the adjustment had been made. code below
ArrayAdapter Snippet
this code is inside the creation of the list item, in which the seekbar is housed
seekBar.setClickable(false);
seekBar.setFocusable(false);
seekBar.setEnabled(false);
/* attach listener */
attachProgressUpdatedListener(seekBar, positionOfItemInList);
AttachProgressUpdatedListener
this method attaches the listener to the seekbar, inside the arrayAdapter class
private void attachProgressUpdatedListener(SeekBar seekBar,
final int position) {
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
int task_id = (Integer) seekBar.getTag();
TaskHandler taskHandler = new TaskHandler(DBAdapter
.getDBAdapterInstance(getContext()));
taskHandler.updateTaskProgress(task_id, progress);
mList.get(position).setProgress(progress);
//need to fire an update to the activity
notifyDataSetChanged();
seekBar.setEnabled(false);
}
public void onStartTrackingTouch(SeekBar seekBar) {
// empty as onStartTrackingTouch listener not being used in
// current implementation
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// empty as onProgressChanged listener not being used in
// current implementation
}
});
}
OnItemCLickListener
this snipped is from the activity which houses the list view.
taskListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
SeekBar sb = (SeekBar) view.findViewById(R.id.seek);
sb.setFocusable(true);
sb.setEnabled(true);
}
});

I had overcame this issue by setting the following attributes to the seekbar in listview item layout file. Then I had the click event of listitem and seekbar working.
android:focusable="false"
android:focusableInTouchMode="false"
<SeekBar
android:id="#+id/playback_icon"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:progress="0"
android:progressDrawable="#drawable/red_scrubber_progress"
android:thumb="#drawable/red_scrubber_control"
android:focusable="false"
android:focusableInTouchMode="false"/>

Related

How to save or change each row state on recyclerview item clicked?

I have created a horizontal recyclerview list. below is the image I have attached.
problem is that I have to change bulb state when everytime user clicked that row from off state to on state and on state to off state.
How do I implement this logic? please help me to find out the solution.
i want to change light color according to user clicks, if he clicks on then it should change its color for that row and vise versa
public void onClick(View view, int position) {
//toast("clicked" + position );
if (!lightClicked){
ImageView lightPopUp = view.findViewById(R.id.row_light_thumbnail);
DrawableCompat.setTint(lightPopUp.getDrawable().mutate(), ContextCompat.getColor(getContext(), R.color.white));
//toast("light on");
lightClicked = true;
}else {
ImageView lightPopUp = view.findViewById(R.id.row_light_thumbnail);
//toast("light off");
DrawableCompat.setTint(lightPopUp.getDrawable().mutate(), ContextCompat.getColor(getContext(), R.color.colorAccent));
lightClicked = false;
}
//View view1 = mLayoutManager.findViewByPosition(position);
}
Dont directly do this change as the recycler view's cells are reused and it wont work as expected, so instead apply the change in the list you are using. You can add a boolean variable in the model class of the list you use to populate the recycler view, and than on its click you can change the boolean's value and call notifydatasetchange on the adapter, and in bind view you should keep an If else condition based on that boolean for the Bulb's image
ie. if true set one image if false set another
declare this :
int selectedPosition=-1;
inside onBindViewHolder:
public void onBindViewHolder(FiltersAdapter.ViewHolder holder, int position) {
if(selectedPosition==position)
holder.itemView.setImageResource(R.drawable.higlihgt_image);
else
holder.itemView.setImageResource(R.drawable.normal_image);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedPosition=position;
notifyDataSetChanged();
}
});
}

How to get seekbar default progress position on activity created

I have the following code in onCreate() Activity:
SeekBar vSeekbar = (SeekBar)findViewById(R.id.seekBar1);
final TextView tvText = (TextView) findViewById(R.id.textView);
//sets seekbar tab position from a randomly generated number...
//when the acitivty is first created I would like the SeekBar position to be set in the `textView`
tvText.setText(vSeekbar.getProgress()); //this is not showing anything...
//the onchangelistener works correctly...
vSeekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
{
#Override
public void onStopTrackingTouch(SeekBar arg0)
{
}
#Override
public void onStartTrackingTouch(SeekBar arg0)
{
}
#Override
public void onProgressChanged(SeekBar arg0, int progress, boolean arg2)
{
tvText.setText(String.valueOf(progress)); //this works fine...
}
});
The seekBar1 position is set by a random number generated when the view is created so no way for me to know beforehand.
How can I get the seekBar1 position when the view is created and set it in the textView.
After random value set to seekbar call vSeekbar.getProgress() method. before you called then only you got zero value.
vSeekbar.setProgress(randomValue());
tvText.setText(vSeekbar.getProgress()+"");
You better limit your random values to the ProgressBar maximum value.
For example if your maximum value is 100 then use the following code: vSeekbar.setProgress(randomValue() % 100);
It will limit the random values to 0 to 99

How do I stop Android ListView from resetting values after scrolling?

I have a ListView with a custom adapter, and each row contains a seekbar the user can set. Each seekbar has a seekBarChangeListener which is set in the adapter, and when a user changes the value of the seekbar in the ListView, the adapter's arraylist is updated. This is what I've got in getView() of the adapter:
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
final ViewHolder viewHolder;
View v = convertView;
if(v == null){
v = inflater.inflate(R.layout.row, null);
viewHolder = new ViewHolder();
viewHolder.contentView = (TextView) v.findViewById(R.id.pref_content);
viewHolder.sliderView = (SeekBar) v.findViewById(R.id.pref_slider);
v.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) v.getTag();
}
// Get initial values
Prompt p = promptList.get(position);
String content = p.getContent();
int sliderLevel = p.sliderLevel();
// Set views with initial values
viewHolder.contentView.setText(content);
viewHolder.sliderView.setMax(noOfLevels);
viewHolder.sliderView.setProgress(sliderLevel);
// Set Change Listener for Seekbar
viewHolder.sliderView.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// Set new level of the Slider in the Array List
promptList.get(position).setSliderLevel(progress);
}
});
return v;
}
So when the user changes the value of the seekbar the ChangeListener gets the object from the ArrayList and sets its new sliderLevel value. However, if I set a new value in the ListView and then scroll down the up again, so that getView is called again, the seekbar returns to its initial value, even though I have changed the value in the arrayList.
Can someone help show me where I'm going wrong here? Thanks
The method onProgressChanged() will be called every time the user changes the SeekBar value. But it will also be called "by system" (I think this happens because the SeekBar is recycled as part of the convertView). That's why it is necessary to check whether fromUser is true:
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (!fromUser) return;
// Set new level of the Slider in the Array List
promptList.get(position).setSliderLevel(progress);
}
In your case, you do not have to call notifyDatasetChanged() because as long as one specific SeekBar is still shown, only the user will change its progress. Once it is hidden (because the user scrolls) and the data for this position have to be shown again later, getView() will be called and the correct value will be set to the SeekBar in the convertView which happens to display your data then.
One other thought (performance reasons): consider only changing the progress value of promptList.get(position) as soon as the user stops manipulating the slider. For this, you can override onStopTrackingTouch() instead of onProgressChanged() and write
promptList.get(position).setSliderLevel(seekBar.getProgress());
So I've managed to solve the issue by moving promptList.get(position).setSliderLevel(progress) from onProgressChanged() to onStopTrackingTouch() in the seekbar's OnSeekBarChangeListener(), and also changing the height of the ListView from wrap_content to match_parent. Both of these things were causing undersirable behaviour.
For some reason onProgressChanged() was being called at runtime, without touching the seekbar at all, even though the changeListener is being set after initialising the seekbar with a value from the arrayList.
Edit: 0X0nosugar's answer explains this behaviour

Android Multiple seekbar in expandable listview

I have expandable ListView with cds as a groups and tracks as a children. Each child has TextView, ImageButton(playButton) and SeekBar.
Now when I clicked one of the playButtons I want to get access to related seekBar.
My problem is that I have global SeekBar and I can't get the right SeekBar object to set my Runnable object correctly. So when I have for example 3 children, I click the first play button, but the third SeekBar is starting.
I have no idea how to resolve it. Any suggestions? This code is in getChildView() method.
SeekBar sb_songProgress;
iv_trackRowIcon.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
int song = l_cds.get(groupPosition).getTracks().get(childPosition).getTrackID();
if(ArtistCardActivity.mediaPlayer.isPlaying())
ArtistCardActivity.mediaPlayer.stop();
ArtistCardActivity.mediaPlayer.newTrack(song);
int finalTime = ArtistCardActivity.mediaPlayer.getDuration();
sb_songProgress.setMax((int) finalTime);
sb_songProgress.setClickable(false);
updateProgress(sb_songProgress);
}
});
public void updateProgress(SeekBar sb)
{
int timeElapsed = ArtistCardActivity.mediaPlayer.getCurrentPosition();
sb_songProgress.setProgress((int) timeElapsed);
durationHandler.postDelayed(updateSeekBarTime, 100);
}
Runnable updateSeekBarTime = new Runnable()
{
public void run()
{
int timeElapsed = ArtistCardActivity.mediaPlayer.getCurrentPosition();
//set seekbar progress
sb_songProgress.setProgress((int) timeElapsed);
durationHandler.postDelayed(this, 100);
}
};
You have to use the ViewHolder pattern (see here, section "Overriding BaseAdapter"), then you will be able to handle seekbar progress with ViewHolder this way:
myHolder.sb_songProgress.setProgress((int) timeElapsed);
Hope it'll work

Unclickable Seekbar in android listview

I have a Listview in my application. Listview rows are clickable. I have introduced a seek bar in each row of a Listview. Despite settings android:clickable="false" for Seekbar in layout xml, I am still able to click on it and move seek bar as desired. I don't want Seekbar to be clickbale but I do want Listview row to clickable.
Any pointers will be appreciated.
Here's my layout file
android:progressDrawable="#drawable/slider_range"
android:thumb="#drawable/slider_thumb"
android:layout_width="80dip"
android:layout_height="12dip"
android:focusable="false"
android:clickable="false"
android:longClickable="false"
seekBarObj.setOnSeekBarChangeListener( new OnSeekBarChangeListener() {
int originalProgress;
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
//Nothing here..
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
originalProgress = seekBar.getProgress();
}
#Override
public void onProgressChanged(SeekBar seekBar, int arg1, boolean fromUser) {
if( fromUser == true){
seekBar.setProgress( originalProgress);
}
}
});
Try setting the enabled attribute to false. You may have to manually adjust the color if you want to avoid it appearing "greyed out"
e.g.
seekBar.setEnabled(false);
I've now got this working using both setFocusable and setEnabled to false, I've implemented a solution to enable the seekbar for a single adjustment when the list item is clicked too if you are interested.
Add focusable=false to the seekbar.

Categories

Resources