I have a custom seekbar with drawable and it is working fine, i am trying to make tooltip text on user action over the seekbar, is there any way without using third party library, i have posted the code below which i am using for custom seekbar
i have also attached a sample progress tooltip that i would like to achieve below
any reference or solution would be appreciated
implementation "com.android.support:appcompat-v7:${android_support_version}"
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progressValue, boolean fromUser) {
seekBar.setThumb(getThumb(progressValue));
TooltipCompat.setTooltipText(seekBar, String.valueOf(progressValue));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
//Do nothing
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//Do nothing
}
});
private Drawable getThumb(int progress) {
View thumbView = LayoutInflater.from(getActivity()).inflate(R.layout.seekbar_tv, null, false);
((TextView) thumbView.findViewById(R.id.tvProgress)).setText(progress + "");
thumbView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
Bitmap bitmap = Bitmap.createBitmap(thumbView.getMeasuredWidth(), thumbView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
thumbView.layout(0, 0, thumbView.getMeasuredWidth(), thumbView.getMeasuredHeight());
thumbView.draw(canvas);
return new BitmapDrawable(getResources(), bitmap);
}
<!--mySeekBarInLayout-->
<SeekBar
android:id="@+id/seekBar_Experience"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="10"
android:progressDrawable="@drawable/survey_seekbar_style"
android:splitTrack="false"
android:thumb="@drawable/survey_seekbar_thum" />
<!--survey_seekbar_thum-->
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="@color/circle_yellow"/>
<size
android:width="30dp"
android:height="30dp"/>
</shape>
</item>
</layer-list>
<!--survey_seekbar_style-->
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@android:id/background"
android:drawable="@drawable/survey_border_shadow"
android:height="1dp"
android:gravity="center">
</item>
<item
android:id="@android:id/progress"
android:height="4dp"
android:gravity="center">
<clip android:drawable="@drawable/survey_seekbar_progress" />
</item>
</layer-list>
<!--survey_border_shadow-->
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:endColor="@color/thr_dark_blue"
android:startColor="@color/thr_dark_blue" />
</shape>
</item>
</layer-list>
<!--survey_seekbar_progress-->
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/progressshape" >
<clip>
<shape
android:shape="rectangle" >
<size android:height="3dp"/>
<corners
android:radius="5dp" />
<solid android:color="@color/thr_dark_blue"/>
</shape>
</clip>
</item>
</layer-list>
You should have your customized textview
and change the text inside onProgressChanged
.
Is that enough? ==> No
You need to change the x
coordinate of the textview
to change it's place to be compatible with seekbar
place.
Code demonstrate that:
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
yourTextView.setText(progress + " miles");
// Get the thumb bound and get its left value
int x = seekBar.getThumb().getBounds().left;
// set the left value to textview x value
yourTextView.setX(x);
}
You can do the following:
1) MainActivity.class:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private SeekBar sb;
private RelativeLayout rlMarker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sb = (SeekBar) findViewById(R.id.sb);
rlMarker = (RelativeLayout) findViewById(R.id.rlMarker);
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
updateMarker(sb, rlMarker, (i + " miles"));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
rlMarker.setVisibility(View.VISIBLE);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
rlMarker.setVisibility(View.GONE);
}
});
//initialize
updateMarker(sb, rlMarker, "0 miles");
}
private void updateMarker(final SeekBar sb,
View rlMarker,
String message) {
final TextView tvProgress = (TextView) rlMarker.findViewById(R.id.tvProgress);
final View vArrow = (View) rlMarker.findViewById(R.id.vArrow);
/**
* According to this question:
* https://stackoverflow.com/questions/20493577/android-seekbar-thumb-position-in-pixel
* one can find the SeekBar thumb location in pixels using:
*/
int width = sb.getWidth()
- sb.getPaddingLeft()
- sb.getPaddingRight();
final int thumbPos = sb.getPaddingLeft()
+ width
* sb.getProgress()
/ sb.getMax() +
//take into consideration the margin added (in this case it is 10dp)
Math.round(convertDpToPixel(10, MainActivity.this));
tvProgress.setText(message);
tvProgress.post(new Runnable() {
@Override
public void run() {
final Display display = ((WindowManager) MainActivity.this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
final Point deviceDisplay = new Point();
display.getSize(deviceDisplay);
//vArrow always follow seekBar thumb location
vArrow.setX(thumbPos - sb.getThumbOffset());
//unlike vArrow, tvProgress will not always follow seekBar thumb location
if ((thumbPos - tvProgress.getWidth() / 2 - sb.getPaddingLeft()) < 0) {
//part of the tvProgress is to the left of 0 bound
tvProgress.setX(vArrow.getX() - 20);
} else if ((thumbPos + tvProgress.getWidth() / 2 + sb.getPaddingRight()) > deviceDisplay.x) {
//part of the tvProgress is to the right of screen width bound
tvProgress.setX(vArrow.getX() - tvProgress.getWidth() + 20 + vArrow.getWidth());
} else {
//tvProgress is between 0 and screen width bounds
tvProgress.setX(thumbPos - tvProgress.getWidth() / 2f);
}
}
});
}
/**
* According to this question:
* https://stackoverflow.com/questions/4605527/converting-pixels-to-dp
* one can convert dp to pixels using the following method:
*/
public static float convertDpToPixel(float dp, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
return px;
}
}
2) activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
android:textSize="40sp"
android:layout_alignParentTop="true"
android:gravity="center"
android:text="Top"
android:layout_above="@id/v"
android:textColor="@android:color/white"/>
<include
layout="@layout/marker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_above="@id/v">
</include>
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_above="@id/sb"
android:id="@+id/v">
</View>
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/sb"
android:layout_centerInParent="true"
android:layout_marginRight="10dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:max="100"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:textSize="40sp"
android:gravity="center"
android:text="Bottom"
android:layout_below="@id/sb"
android:layout_alignParentBottom="true"
android:textColor="@android:color/white"/>
</RelativeLayout>
3) marker.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:id="@+id/rlMarker">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvProgress"
android:gravity="center"
android:padding="10dp"
android:textColor="@android:color/white"
android:background="@drawable/marker_shape"
android:text="0 miles"/>
<View
android:layout_width="20dp"
android:layout_height="20dp"
android:id="@+id/vArrow"
android:gravity="center"
android:rotation="180"
android:layout_below="@id/tvProgress"
android:background="@drawable/marker_arrow_shape"/>
</RelativeLayout>
4) marker_shape.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%">
<shape>
<solid
android:shape="rectangle"
android:color="@color/colorAccent" />
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp"
android:topLeftRadius="5dp"
android:topRightRadius="5dp"/>
</shape>
</rotate>
</item>
</layer-list>
5) marker_arrow_shape.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<rotate
android:fromDegrees="45"
android:toDegrees="45"
android:pivotX="-40%"
android:pivotY="87%">
<shape>
<solid
android:shape="rectangle"
android:color="@color/colorAccent" />
</shape>
</rotate>
</item>
</layer-list>
6) Result:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With