1

I found a couple of questions regarding rangebars (seekbars with two thumbs) on Android, like Android Seekbar with two thumbs or working with SeekBar with two thumbs. All the answers point to components that look quite outdated since Material Design and thus AppCompat was released.

What I'm looking for is a Rangebar that looks like the AppCompatSeekBar with two thumbs. Are there any available libraries or ways to hack into the platform SeekBar so that the available resources can be reused?

Community
  • 1
  • 1
Kirill Rakhman
  • 42,195
  • 18
  • 124
  • 148

1 Answers1

3

This is my first time answering something here. I created my own custom rangebar as follows.

Create the following files.

RangeBar.java

public class RangeBar extends FrameLayout{
int minVal = 0;
int maxVal = 100;
Context context;
ImageView leftThumb;
ImageView rightThumb;
View view;

int leftThumbPos = 0;
int rightThumbPos = 100;


public RangeBar(Context context, AttributeSet attributeSet) {
    super(context, attributeSet);
    this.view = inflate(getContext(), R.layout.range_seekbar, null);
    addView(this.view);
}

public RangeBar(Context context){
    super(context);
    this.context = context;
    this.view = inflate(getContext(), R.layout.range_seekbar, null);
    addView(this.view);
}

public void create() {
    leftThumb = (ImageView)findViewById(R.id.left_thumb);
    rightThumb = (ImageView)findViewById(R.id.right_thumb);

    final View leftBar =  findViewById(R.id.left_bar);
    final View rightBar =  findViewById(R.id.right_bar);
    final View middleBar =  findViewById(R.id.middle_bar);
    final LinearLayout.LayoutParams leftBarLayoutParams = (LinearLayout.LayoutParams) leftBar.getLayoutParams();
    final LinearLayout.LayoutParams rightBarLayoutParams = (LinearLayout.LayoutParams) rightBar.getLayoutParams();
    final LinearLayout.LayoutParams middleBarLayoutParams = (LinearLayout.LayoutParams) middleBar.getLayoutParams();
    final LinearLayout llRangeSeekbar = (LinearLayout)findViewById(R.id.ll_range_seekbar);

    ((TextView)findViewById(R.id.tv_range_max)).setText(maxVal+"");
    ((TextView)findViewById(R.id.tv_range_min)).setText(minVal+"");

    leftThumbPos = Integer.parseInt(((TextView)findViewById(R.id.tv_range_min)).getText()+"");
    rightThumbPos = Integer.parseInt(((TextView)findViewById(R.id.tv_range_max)).getText()+"");

    leftThumb.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            int diff = maxVal - minVal;
            if(diff < 0){
                diff = 100;
                minVal = 0;
                maxVal = 100;
            }
            float width = llRangeSeekbar.getWidth();
            float gap = leftThumb.getWidth();

            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                leftThumb.bringToFront();
                return true;
            }else if (event.getAction() == MotionEvent.ACTION_MOVE ) {
                float temp1 = leftBarLayoutParams.weight;
                float temp2 = middleBarLayoutParams.weight;
                leftBarLayoutParams.weight += event.getX()/width;
                middleBarLayoutParams.weight = 1 - (leftBarLayoutParams.weight + rightBarLayoutParams.weight);

                int tempMaxVal = Integer.parseInt(((TextView)findViewById(R.id.tv_range_max)).getText()+"");
                int tempMinVal = (int)(diff*leftBarLayoutParams.weight + minVal);
                if(tempMinVal > tempMaxVal){
                    tempMinVal = tempMaxVal;
                }
                if(tempMinVal < minVal){
                    tempMinVal = minVal;
                }
                ((TextView)findViewById(R.id.tv_range_min)).setText(tempMinVal + "");

                if(middleBarLayoutParams.weight > gap/width && leftBarLayoutParams.weight >= 0){
                    leftBar.setLayoutParams(leftBarLayoutParams);
                    middleBar.setLayoutParams(middleBarLayoutParams);
                }else {
                    if(leftBarLayoutParams.weight < 0){
                        leftBarLayoutParams.weight = 0;
                        middleBarLayoutParams.weight = 1 - (rightBarLayoutParams.weight + leftBarLayoutParams.weight);
                    }else{
                        middleBarLayoutParams.weight = gap/width + (tempMaxVal - tempMinVal)/(1.0f*diff);
                        leftBarLayoutParams.weight = 1 - (middleBarLayoutParams.weight + rightBarLayoutParams.weight);
                    }
                    leftBar.setLayoutParams(leftBarLayoutParams);
                    middleBar.setLayoutParams(middleBarLayoutParams);
                }
                return true;
            }else if (event.getAction() == MotionEvent.ACTION_UP) {
                leftThumbPos = Integer.parseInt(((TextView)findViewById(R.id.tv_range_min)).getText()+"");
                return true;
            }else
            {
                return false;
            }
        }
    });

    rightThumb.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            int diff = maxVal - minVal;
            if(diff < 0){
                diff = 100;
                minVal = 0;
                maxVal = 100;
            }
            float width = llRangeSeekbar.getWidth();
            float gap = leftThumb.getWidth();

            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                rightThumb.bringToFront();
                return true;
            }else if (event.getAction() == MotionEvent.ACTION_MOVE) {
                float temp1 = middleBarLayoutParams.weight;
                float temp2 = rightBarLayoutParams.weight;

                rightBarLayoutParams.weight -= (event.getX()/width);
                middleBarLayoutParams.weight = 1 - (rightBarLayoutParams.weight + leftBarLayoutParams.weight);

                int tempMinVal = Integer.parseInt(((TextView)findViewById(R.id.tv_range_min)).getText()+"");
                int tempMaxVal = (int)(diff*(1 - rightBarLayoutParams.weight) + minVal);
                if(tempMaxVal < tempMinVal){
                    tempMaxVal = tempMinVal;
                }
                if(tempMaxVal > maxVal){
                    tempMaxVal = maxVal;
                }
                ((TextView)findViewById(R.id.tv_range_max)).setText(tempMaxVal+"");

                if(middleBarLayoutParams.weight > gap/width && rightBarLayoutParams.weight >= 0){
                    rightBar.setLayoutParams(rightBarLayoutParams);
                    middleBar.setLayoutParams(middleBarLayoutParams);
                }else{
                    if(rightBarLayoutParams.weight < 0){
                        rightBarLayoutParams.weight = 0;
                        middleBarLayoutParams.weight = 1 - (rightBarLayoutParams.weight + leftBarLayoutParams.weight);
                    }else {
                        middleBarLayoutParams.weight = gap/width + (tempMaxVal - tempMinVal)/(1.0f*diff);
                        rightBarLayoutParams.weight = 1 - (leftBarLayoutParams.weight + middleBarLayoutParams.weight);
                    }
                    rightBar.setLayoutParams(rightBarLayoutParams);
                    middleBar.setLayoutParams(middleBarLayoutParams);

                }
                return true;
            }else if (event.getAction() == MotionEvent.ACTION_UP) {
                rightThumbPos = Integer.parseInt(((TextView)findViewById(R.id.tv_range_max)).getText()+"");
                return true;
            }
            else
            {
                return false;
            }
        }
    });
}


public int getMinVal() {
    return minVal;
}

public void setMinVal(int minVal) {
    this.minVal = minVal;
}

public int getMaxVal() {
    return maxVal;
}

public void setMaxVal(int maxVal) {
    this.maxVal = maxVal;
}


public int getLeftThumbPos() {
    return leftThumbPos;
}

public void setLeftThumbPos(int leftThumbPos) {
    this.leftThumbPos = leftThumbPos;
}

public int getRightThumbPos() {
    return rightThumbPos;
}

public void setRightThumbPos(int rightThumbPos) {
    this.rightThumbPos = rightThumbPos;
}

}

and range_seekbar.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:layout_height="match_parent">
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:gravity="center"
        android:id="@+id/ll_range_seekbar"
        android:layout_height="wrap_content">

        <View
            android:layout_width="0dp"
            android:layout_weight="0"
            android:id="@+id/left_bar"
            android:background="@color/light_grey"
            android:layout_height="1dp"/>
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:id="@+id/middle_bar"
            android:layout_height="wrap_content">

            <View
                android:layout_width="match_parent"
                android:layout_centerVertical="true"
                android:id="@+id/middle_view"
                android:layout_toRightOf="@+id/left_thumb"
                android:layout_toLeftOf="@+id/right_thumb"
                android:background="@color/color_select_sky_blue"
                android:layout_height="1dp"/>
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/left_thumb"
                android:layout_alignParentLeft="true"
                android:src="@drawable/seek_thumb_normal"/>

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/right_thumb"
                android:layout_alignParentRight="true"
                android:src="@drawable/seek_thumb_normal"/>
        </RelativeLayout>

        <View
            android:layout_width="0dp"
            android:layout_weight="0"
            android:id="@+id/right_bar"
            android:background="@color/light_grey"
            android:layout_height="1dp"/>
    </LinearLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:id="@+id/tv_range_min"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:id="@+id/tv_range_max"/>
    </RelativeLayout>
</LinearLayout>

Use them in the activity as follows.

Test.java

public class Test extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
        RangeBar rangeBar = (RangeBar) findViewById(R.id.rangebar);
        rangeBar.setMinVal(25);
        rangeBar.setMaxVal(50);
        rangeBar.create();
    }
}.

This is the layout file for the activity.

test.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:layout_margin="50dp"
    android:layout_height="match_parent">

    <com.example.pankajkumar.Utils.RangeBar
        android:id="@+id/rangebar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>