Setting size of a triangle (Android) - android

So, I have created an android activity that draws a triangle on the canvas. I also added 4 menus(Color, Enlarge, Shrink, and Reset) to the VM. The color works fine but I'm not quite sure how to resize a triangle in android once that menu button is pressed.The assignment says to just fix the top point of the triangle, and then change the coordinates of the bottom two points of the triangle. Can anyone point me in the right direction on how to do that in Android?
Here's my code, although the implementation of enlarge, shrink, and reset are set up to work with a circle(project I did before), not a triangle. Please note that the "Color" menu works so no need to do that.
public class MainActivity extends Activity
{
final Context context = this;
private Graphics graphic;
private Dialog radiusDialog; //Creates dialog box declaration
private SeekBar red;
private SeekBar green;
private SeekBar blue;
private Button radiusButton;
private TextView progress1;
private TextView progress2;
private TextView progress3;
private TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
graphic = new Graphics(this); //Create new instance of graphics view
setContentView(graphic); //Associates customized view with current screen
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) //This acts as a menu listener to override
{
switch(item.getItemId()) //returns menu item
{
case R.id.Color:
showDialog();
break;
case R.id.Shrink:
graphic.setRadius(graphic.getRadius() -1);
graphic.invalidate();
break;
case R.id.Enlarge:
graphic.setRadius(graphic.getRadius() +1);
graphic.invalidate();
break;
case R.id.Reset:
graphic.setColor(Color.CYAN);
graphic.setRadius(75);
graphic.invalidate();
break;
}
return super.onOptionsItemSelected(item);
}
void showDialog() //creates memory for dialog
{
radiusDialog = new Dialog(context);
radiusDialog.setContentView(R.layout.draw_layout); //binds layout file (radius) with current dialog
radiusDialog.setTitle("Select Color:");
red = (SeekBar)radiusDialog.findViewById(R.id.seekBar1);
green = (SeekBar)radiusDialog.findViewById(R.id.seekBar2);
blue = (SeekBar)radiusDialog.findViewById(R.id.seekBar3);
progress1 = (TextView)radiusDialog.findViewById(R.id.textView2);
progress2 = (TextView)radiusDialog.findViewById(R.id.textView4);
progress3 = (TextView)radiusDialog.findViewById(R.id.textView6);
mychange redC = new mychange();
red.setOnSeekBarChangeListener(redC);
mychange greenC = new mychange();
green.setOnSeekBarChangeListener(greenC);
tv = (TextView)radiusDialog.findViewById(R.id.textView7);
mychange c = new mychange();
blue.setOnSeekBarChangeListener(c);
radiusButton = (Button) radiusDialog.findViewById(R.id.button1);
radiusButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
int color = Color.rgb(red.getProgress(), green.getProgress(), blue.getProgress());
radiusDialog.dismiss();
setContentView(R.layout.activity_main);
setContentView(graphic);
graphic.setColor(color);//Create new instance of graphics view
graphic.invalidate();
}
});
radiusDialog.show(); //shows dialog on screen
}
public class mychange implements OnSeekBarChangeListener{
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
int color = Color.rgb(red.getProgress(), green.getProgress(), blue.getProgress());
tv.setBackgroundColor(color);
progress1.setText(String.valueOf(red.getProgress()));
progress2.setText(String.valueOf(green.getProgress()));
progress3.setText(String.valueOf(blue.getProgress()));
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
}
}
Graphics Class to draw triangle
public class Graphics extends View
{
private Paint paint;
private int radius;
private int color;
public void setColor(int color)
{
this.color = color;
}
public Graphics(Context context) //creates custom view (constructor)
{
super(context);
paint = new Paint(); //create instance of paint
color = Color.CYAN;
paint.setStyle(Paint.Style.FILL); //draw filled shape
radius = 75;
}
#Override
protected void onDraw(Canvas canvas) //override onDraw method
{
super.onDraw(canvas);
paint.setColor(color);
paint.setStyle(Paint.Style.STROKE);
Path path = new Path();
path.moveTo(230, 200);
path.lineTo(330, 300);
path.lineTo(130, 300);
path.close();
canvas.drawPath(path, paint);
}
void setRadius(int radius)
{
this.radius = radius;
invalidate(); //just like repaint method
}
public int getRadius()
{
return radius;
}
}

If the top coordinate remains fixed, you can change the height of the triangle to shrink/enlarge it.
Lets say the triangle is equilateral - all 3 sides have the same length. In this case:
So if the top vertex coordinates are (x, y), the bottom coordinates will be:
(x - side / 2, y + h)
And:
(x + side / 2, y + h)
So your path code should be written as:
float side = Math.sqrt(3) / 2 * height;
Path path = new Path();
path.moveTo(x, y);
path.lineTo(x - side / 2, y + height);
path.lineTo(x + side / 2, y + height);
path.close();

Related

Get View position

I am developing a simple app that produced bubbles on screen on touch. Bubble move around on the screen and get popped when it reaches the border of screen or if a user touches it. I have successfully coded a bubble to pop when reaches borders of the screen but can't figure out a way to detect if the user touched it.
I want to detect if the user touched any bubble on the screen.
Note:- The bubbles are created using custom view. Also I have included some important functions only but can include whole code if you want. Here's the code
public class BubbleActivity extends Activity {
// These variables are for testing purposes, do not modify
private final static int RANDOM = 0;
private final static int SINGLE = 1;
private final static int STILL = 2;
private static int speedMode = RANDOM;
private static final int MENU_STILL = Menu.FIRST;
private static final int MENU_SINGLE_SPEED = Menu.FIRST + 1;
private static final int MENU_RANDOM_SPEED = Menu.FIRST + 2;
private static final String TAG = "Lab-Graphics";
// Main view
private RelativeLayout mFrame;
// Bubble image
private Bitmap mBitmap;
// Display dimensions
private int mDisplayWidth, mDisplayHeight;
// Sound variables
// AudioManager
private AudioManager mAudioManager;
// SoundPool
private SoundPool mSoundPool;
// ID for the bubble popping sound
private int mSoundID;
// Audio volume
private float mStreamVolume;
// Gesture Detector
private GestureDetector mGestureDetector;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Set up user interface
mFrame = (RelativeLayout) findViewById(R.id.frame);
// Load basic bubble Bitmap
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.b64);
}
#Override
protected void onResume() {
super.onResume();
// Manage bubble popping sound
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
// Get the size of the display so this view knows where borders are
mDisplayWidth = mFrame.getWidth();
mDisplayHeight = mFrame.getHeight();
}
}
// Set up GestureDetector
private void setupGestureDetector() {
mGestureDetector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
// Detecting if user touched bubble here
#Override
public boolean onSingleTapConfirmed(MotionEvent event) {
// Trying to get bubble position but can't just get x=0, y=0 tried
// many things
Log.d(TAG,""+((ViewGroup)mFrame).getChildCount());
for(int i=0; i<((ViewGroup)mFrame).getChildCount(); ++i) {
View nextChild = ((ViewGroup)mFrame).getChildAt(i);
Rect rect = new Rect();
nextChild.getLocalVisibleRect(rect);
int[] location = new int[2];
nextChild.getLocationOnScreen(location);
Log.d(TAG, "X = " + location[0] + " Y = " + location[1]);
}
if(event.getAction() == MotionEvent.ACTION_DOWN){
BubbleView bubbleView = new BubbleView(getApplicationContext(), event.getX(),event.getY());
bubbleView.start();
mFrame.addView(bubbleView);
}
return true;
}
});
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// TODO - delegate the touch to the gestureDetector
return mGestureDetector.onTouchEvent(event);
}
#Override
protected void onPause() {
// TODO - Release all SoundPool resources
super.onPause();
}
// BubbleView is a View that displays a bubble.
// This class handles animating, drawing, popping amongst other actions.
// A new BubbleView is created for each bubble on the display
private class BubbleView extends View {
private static final int BITMAP_SIZE = 64;
private static final int REFRESH_RATE = 40;
private final Paint mPainter = new Paint();
private ScheduledFuture<?> mMoverFuture;
private int mScaledBitmapWidth;
private Bitmap mScaledBitmap;
// location, speed and direction of the bubble
private float mXPos, mYPos, mDx, mDy;
private long mRotate, mDRotate;
public BubbleView(Context context, float x, float y) {
super(context);
log("Creating Bubble at: x:" + x + " y:" + y);
// Create a new random number generator to
// randomize size, rotation, speed and direction
Random r = new Random();
// Creates the bubble bitmap for this BubbleView
createScaledBitmap(r);
// Adjust position to center the bubble under user's finger
mXPos = x - mScaledBitmapWidth / 2;
mYPos = y - mScaledBitmapWidth / 2;
// Set the BubbleView's speed and direction
setSpeedAndDirection(r);
// Set the BubbleView's rotation
setRotation(r);
mPainter.setAntiAlias(true);
}
// Start moving the BubbleView & updating the display
private void start() {
// Creates a WorkerThread
ScheduledExecutorService executor = Executors
.newScheduledThreadPool(1);
// Execute the run() in Worker Thread every REFRESH_RATE
// milliseconds
// Save reference to this job in mMoverFuture
mMoverFuture = executor.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
// TODO - implement movement logic.
// Each time this method is run the BubbleView should
// move one step. If the BubbleView exits the display,
// stop the BubbleView's Worker Thread.
// Otherwise, request that the BubbleView be redrawn.
if(!isOutOfView()){
moveWhileOnScreen();
}
else{
stop(true);
}
}
}, 0, REFRESH_RATE, TimeUnit.MILLISECONDS);
}
private synchronized boolean intersects(float x, float y) {
// TODO - Return true if the BubbleView intersects position (x,y)
return false;
}
// Cancel the Bubble's movement
// Remove Bubble from mFrame
// Play pop sound if the BubbleView was popped
private void stop(final boolean popped) {
if (null != mMoverFuture && mMoverFuture.cancel(true)) {
// This work will be performed on the UI Thread
mFrame.post(new Runnable() {
#Override
public void run() {
// TODO - Remove the BubbleView from mFrame
if (popped) {
log("Pop!");
// TODO - If the bubble was popped by user,
// play the popping sound
mFrame.removeView(BubbleView.this);
//mMoverFuture.cancel(true);
mSoundPool.play(mSoundID, 1, 1, 1, 0, 1);
}
log("Bubble removed from view!");
}
});
}
}
// Change the Bubble's speed and direction
private synchronized void deflect(float velocityX, float velocityY) {
log("velocity X:" + velocityX + " velocity Y:" + velocityY);
//TODO - set mDx and mDy to be the new velocities divided by the REFRESH_RATE
mDx = velocityX/REFRESH_RATE;
mDy = velocityY/REFRESH_RATE;
}
// Draw the Bubble at its current location
#Override
protected synchronized void onDraw(Canvas canvas) {
// TODO - save the canvas
canvas.save();
// TODO - increase the rotation of the original image by mDRotate
mRotate = mRotate + mDRotate;
// TODO Rotate the canvas by current rotation
canvas.rotate(mRotate, mXPos + mScaledBitmapWidth/2, mYPos + mScaledBitmapWidth/2);
// TODO - draw the bitmap at it's new location
canvas.drawBitmap(mScaledBitmap, mXPos, mYPos,mPainter);
// TODO - restore the canvas
canvas.restore();
}
private synchronized boolean moveWhileOnScreen() {
// TODO - Move the BubbleView
// Returns true if the BubbleView has exited the screen
mXPos = mDx+mXPos;
mYPos = mDy+mYPos;
postInvalidate();
return false;
}
private boolean isOutOfView() {
// TODO - Return true if the BubbleView has exited the screen
if(mXPos + mScaledBitmapWidth/2 >= mDisplayWidth - mScaledBitmapWidth/2 || mXPos <0
||mYPos + mScaledBitmapWidth/2 >= mDisplayHeight - mScaledBitmapWidth/2 || mYPos <0){
return true;
}
return false;
}
}
Update :-
To clarify a bit, I want to get the location of all the bubbles on the screen and then compare them to event.getX() and event.getY() to detect if i tapped on any bubble. II have to check bubble tap in onSingleTapConfirmed(). I am correctly able to get the total number of bubbles but can't detect their location on the screen.
for(int i=0; i<((ViewGroup)mFrame).getChildCount(); ++i) {
View nextChild = ((ViewGroup)mFrame).getChildAt(i);
Rect rect = new Rect();
nextChild.getLocalVisibleRect(rect);
int[] location = new int[2];
nextChild.getLocationOnScreen(location);
Log.d(TAG, "X = " + location[0] + " Y = " + location[1]);
}
Above code gives the correct number of bubbles but return their coordinates as 0,0.
In your onSingleTapConfirmed function, try the following to iterate through your BubbleViews and pass the Event X and Y coordinates on.
for(int i=0;i<mFrame.getChildCount();i++){
BubbleView bubbleThis = (BubbleView) mFrame.getChildAt(i);
if (bubbleThis.intersects(event.getX(),event.getY())){
bubbleThis.stop(true);
return true;
}
}
The function in BubbleView should then return true if the X and Y fall inside its boundaries. I will add the function inside intersects function in BubbleView as clarification:
private synchronized boolean intersects(float x, float y) {
if ( (x>mXPos && x<(mXPos+mScaledBitmapWidth)) && (y>mYPos && y<(mYPos+mScaledBitmapWidth)) ) {
return true;
}
return false;
}
If you want to know if a user tapped a bubble, set its onClickListener. If you want to know if the user just touched it, override its onTouchEvent and look for ACTION_DOWN.
How are you implementing the onDown() method of your SimpleOnGestureListener?
Please take a look at these answers:
Gesture Detector not working
Android GestureDetector with SimpleOnGestureListener within SurfaceView
Detect which View was tapped in the onSingleTapConfirmed method
Bubble is circle in shape, so you just need to compare its radius with the distance between bubble center and the position.
mRadius = radius of the bubble
mDistance = distance between (event.getX(), event.getY()) and bubble center (mXPos + mRadius, mYPos + mRadius)

Custom ProgressBar

I am trying to create a ProgresBar that looks like the following:
So far, I have created an object which extends ProgressBar, and now I am trying to figure out what my next step is.
I know that I need to override onDraw() with some logic that will decide how many squares to color in. This is trivial.
What I don't know how to do is get these squares in the first place. How can I replace the default drawable, so when I add my custom bar in the layout I can see something like my image?
try this custom Drawable:
class ProgressDrawable extends Drawable {
private static final int NUM_RECTS = 10;
Paint mPaint = new Paint();
#Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
#Override
public void draw(Canvas canvas) {
int level = getLevel();
Rect b = getBounds();
float width = b.width();
for (int i = 0; i < NUM_RECTS; i++) {
float left = width * i / NUM_RECTS;
float right = left + 0.9f * width / NUM_RECTS;
mPaint.setColor((i + 1) * 10000 / NUM_RECTS <= level? 0xff888888 : 0xffbbbbbb);
canvas.drawRect(left, b.top, right, b.bottom, mPaint);
}
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
and test it with the following in onCreate:
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
final ProgressBar pb = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);
Drawable d = new ProgressDrawable();
pb.setProgressDrawable(d);
pb.setPadding(20, 20, 20, 0);
ll.addView(pb);
OnSeekBarChangeListener l = new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int newProgress = pb.getMax() * progress / seekBar.getMax();
Log.d(TAG, "onProgressChanged " + newProgress);
pb.setProgress(newProgress);
}
};
int[] maxs = {4, 10, 60, 110};
for (int i = 0; i < maxs.length; i++) {
SeekBar sb = new SeekBar(this);
sb.setMax(maxs[i]);
sb.setOnSeekBarChangeListener(l);
sb.setPadding(20, 20, 20, 0);
ll.addView(sb);
}
setContentView(ll);

Canvas not updating in real device

I trying to make a draw line using canvas. It has 0 value when the Activity is loaded then I have a Button that has click listener to change the value and draw a line. It works in emulator well but when I run in my real device (android version 4.1) the canvas didn't change but I know that I hit the button because I put a toast inside the click listener. This is really weird.
Do anyone encounter the same problem before?
any thoughts will be highly appreciated.
Below is my Activity:
public class MainActivity extends Activity{
private Paint paintFree = new Paint();
private Paint paintLocal = new Paint();
private Paint paintRoaming = new Paint();
private int freeUsage = 0;
private int localUsage = 0;
private int roamingUsage = 0;
private int freeBarPoints;
private int localBarPoints;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
overridePendingTransition(0, 0);
line();
((Button) findViewById(R.id.btn1)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
freeUsage = 12;
localUsage = 1;
roamingUsage = 1;
line();
Log.i("Hit Btn1", "True");
Toast.makeText(v.getContext(), "Hit Btn1", Toast.LENGTH_SHORT).show();
}
});
}
class Draw extends View{
public Draw(Context context) {
super(context);
// TODO Auto-generated constructor stub
paintFree.setStrokeWidth(20f);
paintLocal.setStrokeWidth(20f);
paintRoaming.setStrokeWidth(20f);
if (freeUsage == 0){
paintFree.setColor(Color.GRAY);
} else {
paintFree.setColor(Color.rgb(70, 227, 78));
}
if (localUsage == 0){
paintLocal.setColor(Color.GRAY);
} else {
paintLocal.setColor(Color.rgb(238, 232, 102));
}
if (roamingUsage == 0){
paintRoaming.setColor(Color.GRAY);
} else {
paintRoaming.setColor(Color.rgb(101, 177, 231));
}
}
protected void onDraw(Canvas canvas) {
int maxBarLength = canvas.getWidth() * 4 / 5;
double totalBarPoints = freeUsage + localUsage + roamingUsage;
freeBarPoints = (int) Math.round(freeUsage * maxBarLength / totalBarPoints);
localBarPoints = (int) Math.round(localUsage * maxBarLength / totalBarPoints);
// need not compute the roaming bar points
int localStartX = 0 + Math.round(freeBarPoints);
int roamingStartX = (int) localStartX + Math.round(localBarPoints);
canvas.drawLine(0, 10, localStartX, 10, paintFree);
canvas.drawLine(localStartX, 10, roamingStartX, 10, paintLocal);
canvas.drawLine(roamingStartX, 10, maxBarLength, 10, paintRoaming);
}
}
public void line(){
Draw draw;
draw = new Draw(this);
((LinearLayout) findViewById(R.id.linear)).addView(draw);
}
}
You need to add an onMeasure implementation to your Draw class. Take a look at http://developer.android.com/training/custom-views/custom-drawing.html for more details.

delaye canvas update using Timer Class

I created a view type-class in which onDraw() method i am drawing some boxes. The thing in which i am not getting succeed is that, i want to disappear these boxes after 3-5 second. For this i am using timer and timerTask. In TimerTask i am overriding the method run() which changes the color of Paint object to white. The background color is also white so it will give the effect that boxes are erased. Can you guys help me out??
public class PlayView extends View
{
private float width,height;
private int touchatX, touchatY;
private boolean isanyBox, clearCanvas;
private Point points[];
private Paint box;
Timer timer;
TimerTask task;
// Set the number of points to be generated so we print that number of boxes on the board
public void nPoints(int n)
{
points = new Point[n];
box = new Paint();
box.setColor(Color.BLUE);
}
public void init()
{
isanyBox = false;
clearCanvas = true;
timer = new Timer();
task = new TimerTask()
{
#Override
public void run()
{
box.setColor(Color.WHITE);
}
};
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
// TODO Auto-generated method stub
width = w/6f;
height = h/6f;
Log.d("playview", getWidth()+" "+getHeight());
super.onSizeChanged(w, h, oldw, oldh);
}
public PlayView(Context context)
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
init();
}
// Randomly generate the points and draw boxes on these points
public void generatePoints(int np)
{
Time sec = new Time();
Random random_Xpoints = new Random();
Random random_Ypoints = new Random();
random_Xpoints.setSeed(sec.second);
random_Ypoints.setSeed(sec.second);
nPoints(np); // set the number of points to be generated
for(int i=0; i<np; i++)
{
points[i] = new Point();
points[i].setX( ((random_Xpoints.nextInt(getWidth())/(int)width)*(int)width));
points[i].setY( ((random_Ypoints.nextInt(getHeight())/(int)height)*(int)height));
Log.d("Point "+1, points[i].getX()+" "+points[i].getY());
}
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
// TODO Auto-generated method stub
invalidate();
isanyBox = true;
touchatX = (int) ((int) (event.getX()/width)*width);
touchatY = (int) ((int) (event.getY()/height)*height);
Log.d("onTouchEvent", event.getX()+" "+event.getY()+" "+touchatX+" "+touchatY);
invalidate();
return super.onTouchEvent(event);
}
public void onDraw(Canvas canvas)
{
Paint lineColor = new Paint();
lineColor.setColor(Color.BLACK);
//Box property
Paint boxColor = new Paint();
boxColor.setColor(Color.BLUE);
//Draw horizontal lines
for(int i=0; i<6; i++)
{
canvas.drawLine(0, i*height, getWidth(), i*height, lineColor);
}
//Draw vertical lines
for(int j=0; j<6; j++)
{
canvas.drawLine(j*width, 0, j*width, getHeight(), lineColor);
}
if(isanyBox)
{
canvas.drawRect(touchatX+2, touchatY+2, touchatX+width-1, touchatY+height-2, boxColor);
}
generatePoints(5);
for(int j=0; j<5; j++)
{
canvas.drawRect(points[j].getX()+2, points[j].getY()+2, points[j].getX()+width-1, points[j].getY()+height-2, box);
Log.d("BoxColor", ""+box);
}
if(clearCanvas)
{
timer.schedule(task, 3000);
clearCanvas = false;
invalidate();
}
}
}
call invalidate(); after changing the color. This will force the system to call onDraw() again.
#Override
public void run()
{
box.setColor(Color.WHITE);
invalidate();
}
edit:
I've never liked timers and now I now why, that's why and also for some reason the Android team suggests people not to use them as it can be read here: http://developer.android.com/reference/java/util/Timer.html
because you're on a class that extends View, you should just call postDelayed();
if(clearCanvas)
{
clearCanvas = false;
postDelayed(new Runnable{
#Override
public void run(){
box.setColor(Color.WHITE);
invalidate();
}
}, 3000);
}

Android seekbar with custom thumb having dynamic text inside it

I want to create android custom SeekBar having thumb with text inside it to show current seek position.
Here is my code:
SeekBar sb;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_seek_bar_activity);
sb = (SeekBar)findViewById(R.id.slider);
sb.setMax(100);
sb.setProgress(10);
BitmapDrawable bd = writeOnDrawable(R.drawable.star2, Double.toString(50));
sb.setThumb(bd);
sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
int pos = sb.getProgress();
double star = pos/(20.0);
TextView tv = (TextView)findViewById(R.id.percent);
tv.setText(Double.toString(star)+"%");
BitmapDrawable bd = writeOnDrawable(R.drawable.star2, Double.toString(star));
bd.setBounds(new Rect(0,0,
bd.getIntrinsicWidth(),
bd.getIntrinsicHeight()
));
seekBar.setThumb(bd);
}
#Override
public void onStartTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
}
});
}
public BitmapDrawable writeOnDrawable(int drawableId, String text){
Bitmap bm = BitmapFactory.decodeResource(getResources(), drawableId).copy(Bitmap.Config.ARGB_8888, true);
Paint paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(Color.BLACK);
paint.setTextSize(10);
Canvas canvas = new Canvas(bm);
canvas.drawText(text, 0, bm.getHeight()/2, paint);
return new BitmapDrawable(bm);
}
but when I move thumb it goes to the beginning of the seek bar.
Does anyone have solution to move custom thumb with seekbar position?
I use SeekBar to display a timer countdown in my app. Inside the timer thumb I show the current SeekBar progress number using the below code:
SeekBar timerBar = (SeekBar) findViewById(R.id.seekBarTimer);
if (timerBar != null) {
timerBar.setMax((int) (Settings.countdownSeconds + 1));
timerBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar arg0) {
}
#Override
public void onStartTrackingTouch(SeekBar arg0) {
}
#Override
public void onProgressChanged(SeekBar timerBar, int arg1, boolean arg2) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.seek_thumb);
Bitmap bmp = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas c = new Canvas(bmp);
String text = Integer.toString(timerBar.getProgress());
Paint p = new Paint();
p.setTypeface(Typeface.DEFAULT_BOLD);
p.setTextSize(14);
p.setColor(0xFFFFFFFF);
int width = (int) p.measureText(text);
int yPos = (int) ((c.getHeight() / 2) - ((p.descent() + p.ascent()) / 2));
c.drawText(text, (bmp.getWidth()-width)/2, yPos, p);
timerBar.setThumb(new BitmapDrawable(getResources(), bmp));
}
});
timerBar.setProgress(0);
}
The R.drawable.seek_thumb drawable is my thumb drawable.
I got solution now, in setBound() method I was passing top left as 0, that's why it is showing seek bar at beginning. After doing following change I got it works.
Call setThumbPos() method in onProgressChanged() event
public void setThumbPosition(SeekBar seekBar){
int max = seekBar.getMax();
int available = seekBar.getWidth() - seekBar.getPaddingLeft() - seekBar.getPaddingRight();
float scale = max > 0 ? (float) seekBar.getProgress() / (float) max : 0;
//scale = 1;
int pos = sb.getProgress();
double star = pos/(20.0);
BitmapDrawable bd = writeOnDrawable(R.drawable.star2, Double.toString(star));
int thumbWidth = bd.getIntrinsicWidth();
int thumbHeight = bd.getIntrinsicHeight();
//available -= thumbWidth;
int thumbPos = (int) (scale * available);
if(thumbPos <= 0+thumbWidth){
thumbPos += (thumbWidth/2);
}else if(thumbPos >= seekBar.getWidth()-thumbWidth){
thumbPos -= (thumbWidth/2);
}
bd.setBounds(new Rect(thumbPos,0,
thumbPos+bd.getIntrinsicWidth(),
bd.getIntrinsicHeight()
));
seekBar.setThumb(bd);
TextView tv = (TextView)findViewById(R.id.percent);
tv.setText(Double.toString(star)+"%");
}
I ended up using this simple solution. Its probably not as high-performance as say a proper custom SeekBar, however its really easy to plug into an existing layout, and use any label or other view on top of the SeekBar thumb.
protected void positionThumbLabel(SeekBar seekBar, TextView label)
{
Rect tr = seekBar.getThumb().getBounds();
label.setWidth(tr.width());
label.setX(tr.left + seekBar.getPaddingLeft());
}
With some minor changes you can position an overlay relative to the center of the thumb:
protected void positionThumbOverlayCenter(SeekBar seekBar, View overlay)
{
Rect tr = seekBar.getThumb().getBounds();
overlay.setX(tr.centerX() - (overlay.getWidth() * 0.5f) + seekBar.getPaddingLeft());
}
Pick a solution that match your situation here: http://www.helptouser.com/code/10722746-add-dynamic-text-over-android-seekbar-thumb.html

Categories

Resources