我正在尝试在Android 2.2中制作这个自定义SeekBar,我所做的一切似乎都是错的!我试图在SeekBar的拇指图像上显示搜索栏的值。有人有这方面的经验吗?
答案 0 :(得分:20)
我假设你已经扩展了基类,所以你有类似的东西:
public class SeekBarHint extends SeekBar {
public SeekBarHint (Context context) {
super(context);
}
public SeekBarHint (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public SeekBarHint (Context context, AttributeSet attrs) {
super(context, attrs);
}
}
现在,您使用自己的一些代码覆盖onDraw
方法。插入以下内容:
@Override
protected void onDraw(Canvas c) {
super.onDraw(c);
}
现在,你想在拇指附近画一些文字,但没有一种方便的方法来获得拇指的x位置。我们只需要一点点数学。
@Override
protected void onDraw(Canvas c) {
super.onDraw(c);
int thumb_x = ( (double)this.getProgress()/this.getMax() ) * (double)this.getWidth();
int middle = this.getHeight()/2;
// your drawing code here, ie Canvas.drawText();
}
答案 1 :(得分:14)
我采用了不同的方法,提供了更多定制拇指的可能性。最终输出如下所示:
首先,您必须设计将设置为拇指可绘制的布局。
<强> layout_seekbar_thumb.xml 强>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="@dimen/seekbar_thumb_size"
android:layout_height="@dimen/seekbar_thumb_size"
android:background="@drawable/ic_seekbar_thumb_back"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tvProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textColor="#000000"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
根据您的要求,此处seekbar_thumb_size
可以是任何小尺寸。我在这里使用了30dp
。对于背景,您可以使用您选择的任何可绘制/图标。
现在您需要将此视图设置为thumb drawable,因此请使用以下代码获取它:
View thumbView = LayoutInflater.from(YourActivity.this).inflate(R.layout.layout_seekbar_thumb, null, false);
我建议在onCreate()
初始化此视图,因此无需一次又一次地对其进行充气。
现在,当更改seekBar进度时,将此视图设置为拇指可绘制。在代码中添加以下方法:
public Drawable getThumb(int progress) {
((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);
}
现在从onProgressChanged()
调用此方法。
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// You can have your own calculation for progress
seekBar.setThumb(getThumb(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
注意:在初始化getThumb()
时使用默认值对其进行初始化时,也请调用seekBar
方法。
使用此方法,您可以获得有关进度更改的任何自定义视图。
答案 2 :(得分:7)
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
int val = (progress * (seekBar.getWidth() - 2 * seekBar.getThumbOffset())) / seekBar.getMax();
text_seekbar.setText("" + progress);
text_seekbar.setX(seekBar.getX() + val + seekBar.getThumbOffset() / 2);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
text_seekbar.setVisibility(View.VISIBLE);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
text_seekbar.setVisibility(View.GONE);
}
});
答案 3 :(得分:6)
这对我有用
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int val = (progress * (seekBar.getWidth() - 2 * seekBar.getThumbOffset())) / seekBar.getMax();
_testText.setText("" + progress);
_testText.setX(seekBar.getX() + val + seekBar.getThumbOffset() / 2);
}
答案 4 :(得分:6)
嘿,我找到了另一个解决方案,似乎更简单:
private void setText(){
int progress = mSeekBar.getProgress();
int max= mSeekBar.getMax();
int offset = mSeekBar.getThumbOffset();
float percent = ((float)progress)/(float)max;
int width = mSeekBar.getWidth() - 2*offset;
int answer =((int)(width*percent +offset - mText.getWidth()/2));
mText.setX(answer);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
setText();
mText.setText(""+progress);
}
答案 5 :(得分:5)
以下代码会将您的TextView
中心与您的SeekBar
拇指中心对齐。
YOUR_TEXT_VIEW width 必须是xml中的 wrap_content 。
希望此代码能为您提供帮助。
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
YOUR_TEXT_VIEW.setText(Integer.toString(progress));
double pourcent = progress / (double) seekBar.getMax();
int offset = seekBar.getThumbOffset();
int seekWidth = seekBar.getWidth();
int val = (int) Math.round(pourcent * (seekWidth - 2 * offset));
int labelWidth = YOUR_TEXT_VIEW.getWidth();
YOUR_TEXT_VIEW.setX(offset + seekBar.getX() + val
- Math.round(pourcent * offset)
- Math.round(pourcent * labelWidth/2));
}
答案 6 :(得分:4)
我使用这个库来创建可绘制的文本视图,并以编程方式将该drawable放入thumb中。
https://github.com/amulyakhare/TextDrawable
代码是这样的:
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
String dynamicText = String.valueOf(progress);
TextDrawable drawable = TextDrawable.builder()
.beginConfig()
.endConfig()
.buildRoundRect(dynamicText , Color.WHITE ,20);
seekBar.setThumb(drawable);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
答案 7 :(得分:2)
对我来说工作不错
有一点硬编码)
请写下smbd可能有的改进
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v7.widget.AppCompatSeekBar;
import android.util.AttributeSet;
import android.util.TypedValue;
public class CustomSeekBar extends AppCompatSeekBar {
@SuppressWarnings("unused")
private static final String TAG = CustomSeekBar.class.getSimpleName();
private Paint paint;
private Rect bounds;
public String dimension;
public CustomSeekBar(Context context) {
super(context);
init();
}
public CustomSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setTextSize(sp2px(14));
bounds = new Rect();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String label = String.valueOf(getProgress()) + dimension;
paint.getTextBounds(label, 0, label.length(), bounds);
float x = (float) getProgress() * (getWidth() - 2 * getThumbOffset()) / getMax() +
(1 - (float) getProgress() / getMax()) * bounds.width() / 2 - bounds.width() / 2
+ getThumbOffset() / (label.length() - 1);
canvas.drawText(label, x, paint.getTextSize(), paint);
}
private int sp2px(int sp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
}
}
答案 8 :(得分:0)
我创建了这个示例,以显示如何支持textview以适应不同类型的屏幕尺寸以及如何计算Thumb的实际位置,因为有时位置可能为0。
public class CustomProgressBar extends RelativeLayout implements AppCompatSeekBar.OnSeekBarChangeListener {
@BindView(R.id.userProgressBar)
protected AppCompatSeekBar progressSeekBar;
@BindView(R.id.textPorcent)
protected TextView porcent;
@BindView(R.id.titleIndicator)
protected TextView title;
public CustomProgressBar(Context context) {
super(context);
init();
}
public CustomProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.custom_progressbar_view, this, true);
ButterKnife.bind(this);
setColors(R.color.green, R.color.progress_bar_remaining);
progressSeekBar.setPadding(0, 0, 0, 0);
progressSeekBar.setOnSeekBarChangeListener(this);
}
private void setPorcentTextViewPosition(float widthView) {
int width = CoreUtils.getScreenSize().x;
float xPosition = ((float) progressSeekBar.getProgress() / 100) * width;
float finalPosition = xPosition - (widthView / 2f);
if (width - xPosition < widthView) {
porcent.setX(width - widthView);
} else if (widthView < finalPosition) {
porcent.setX(finalPosition);
}
}
public void setColors(int progressDrawable, int remainingDrawable) {
LayerDrawable layer = (LayerDrawable) progressSeekBar.getProgressDrawable();
Drawable background = layer.getDrawable(0);
Drawable progress = layer.getDrawable(1);
background.setColorFilter(ContextCompat.getColor(getContext(), remainingDrawable), PorterDuff.Mode.SRC_IN);
progress.setColorFilter(ContextCompat.getColor(getContext(), progressDrawable), PorterDuff.Mode.SRC_IN);
}
public void setValues(int progress, int remaining) {
int value = (progress * remaining) / 100;
progressSeekBar.setMax(remaining);
porcent.setText(String.valueOf(value).concat("%"));
porcent.post(new Runnable() {
@Override
public void run() {
setPorcentTextViewPosition(porcent.getWidth());
}
});
progressSeekBar.setProgress(value);
}
public void setTitle(String title) {
this.title.setText(title);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
答案 9 :(得分:0)
IMO最好的方法是通过代码来实现。真的不是那么可怕,毕竟我们都是程序员:)
class ThumbDrawable(context: Context) : Drawable() {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private val textBounds = Rect()
private var shadowColor = context.resources.getColor(R.color.wallet_screen_option_shadow)
private val size = context.resources.getDimensionPixelSize(R.dimen.thumbRadius).toFloat()
private val textSize = context.resources.getDimensionPixelSize(R.dimen.thumbTextSize).toFloat()
var progress: Int = 0
init {
textPaint.typeface = Typeface.createFromAsset(context.assets, "font/avenir_heavy.ttf")
val accentColor = context.resources.getColor(R.color.accent)
paint.color = accentColor
textPaint.color = accentColor
textPaint.textSize = textSize
paint.setShadowLayer(size / 2, 0f, 0f, shadowColor)
}
override fun draw(canvas: Canvas) {
Timber.d("bounds: $bounds")
val progressAsString = progress.toString()
canvas.drawCircle(bounds.left.toFloat(), bounds.top.toFloat(), size, paint)
textPaint.getTextBounds(progressAsString, 0, progressAsString.length, textBounds)
//0.6f is cause of the avenirs spacing, should be .5 for proper font
canvas.drawText(progressAsString, bounds.left.toFloat() - textBounds.width() * 0.6f, bounds.top.toFloat() - size * 2, textPaint)
}
override fun setAlpha(alpha: Int) {
}
override fun getOpacity(): Int {
return PixelFormat.OPAQUE
}
override fun setColorFilter(colorFilter: ColorFilter?) {
}
}
以及您的seekbar实现中
class CustomSeekBar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
SeekBar(context, attrs, defStyleAttr) {
init {
thumb = ThumbDrawable(context)
setPadding(0, 0, 0, 0);
}
override fun invalidate() {
super.invalidate()
if (thumb is ThumbDrawable) (thumb as ThumbDrawable).progress = progress
}
}
最终结果是这样的 JSR223 Test Elements
答案 10 :(得分:0)
将TextView添加到布局中。添加onSeekBarChangeListener
。
您将需要精确度,以便文本恰好位于搜索栏拇指的中间,您需要进行一些计算。这是因为文本的宽度不同。假设您要显示0到150之间的数字。188的宽度将不同于111。因此,您显示的文本将始终向一侧倾斜。
解决该问题的方法是测量文本的宽度,将其从搜索栏拇指的宽度中删除,将其除以2,然后将其添加到接受的答案中给出的结果中。现在,您无需担心数字范围有多大。这是代码:
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
val value = progress * (seekBar.width - 2 * seekBar.thumbOffset) / seekBar.max
label.text = progress.toString()
label.measure(0, 0)
val textWidth = label.measuredWidth
val firstRemainder = seekThumbWidth - textWidth
val result = firstRemainder / 2
label.x = (seekBar.x + value + result)
}