Context: I want to build a horizontal progress bar with some values and want to put some text that move along below this progress bar. So my final ideia is something like this (I already have the progress bar built I only left the text views below)
My current code is something like this:
This is my StackedHorizontalProgressBar class:
public class StackedHorizontalProgressBar extends ProgressBar {
private Paint paint;
int primary_progress, max_value;
public StackedHorizontalProgressBar(Context context) {
super(context);
init();
}
public StackedHorizontalProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
#Override public synchronized void setMax(int max) {
this.max_value = max;
super.setMax(max);
}
#Override public synchronized void setProgress(int progress) {
if (progress > max_value) {
progress = max_value;
}
this.primary_progress = progress;
super.setProgress(progress);
}
#Override public synchronized void setSecondaryProgress(int secondaryProgress) {
if ((primary_progress + secondaryProgress) > max_value) {
secondaryProgress = (max_value - primary_progress);
}
super.setSecondaryProgress(primary_progress + secondaryProgress);
}
private void init() {
paint = new Paint();
paint.setColor(Color.BLACK);
primary_progress = 0;
max_value = 100;
}
}
This is my Main Activity layout (that uses above class)
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<github.nisrulz.stackedhorizontalprogressbar.StackedHorizontalProgressBar
android:id="#+id/stackedhorizontalprogressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:progressDrawable="#drawable/stacked_horizontal_progress"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="16dp" />
</android.support.constraint.ConstraintLayout>
This is my MainActivity class:
public class MainActivity extends AppCompatActivity {
int max = 100;
int countPrimary = 20;
int countSecondary = 30;
StackedHorizontalProgressBar stackedHorizontalProgressBar;
TextView txt_primary, txt_secondary;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
stackedHorizontalProgressBar =
(StackedHorizontalProgressBar) findViewById(R.id.stackedhorizontalprogressbar);
stackedHorizontalProgressBar.setMax(max);
stackedHorizontalProgressBar.setProgress(countPrimary);
txt_primary.setText("Primary Value : " + countPrimary + "%");
stackedHorizontalProgressBar.setSecondaryProgress(countSecondary);
txt_secondary.setText("Secondary Value : " + countSecondary + "%");
}
}
I think I must use canvas for this, so if there is anyone with experience with this that can help me.
public class ProgressBarAvtivity extends AppCompatActivity {
ProgressBar progressBar;
TextView tvProgress;
int d = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progress_bar_avtivity);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
progressBar.setProgress(d);
tvProgress = (TextView)findViewById(R.id.tvProgress);
tvProgress.setText(String.valueOf(d));
if (d > 40) {
tvProgress.setX(((width )* d / 100) - (d/2));
}
else {
tvProgress.setX(((width )* d / 100));
}
}}
Related
I have a trapezoid shape created in custom view using below code.
#Override
protected void onDraw(Canvas canvas) {
trapezoidPath.moveTo(0,0);
trapezoidPath.lineTo(getWidth() ,0);
trapezoidPath.lineTo(getWidth() , altitude);
trapezoidPath.lineTo(0,getHeight());
trapezoidPath.lineTo(0,0);
trapezoidPath.close();
canvas.drawPath(trapezoidPath,paintTrapezoid);
}
The drawn shape looks like this.
I want to move (0,height) point to top until trapezoid shape become a rectangle. After that I want to move bottom line up until shape become a line.
Is there any way to access created path lines and it's point and manipulate them to achieve what I want ? If not how can I achieve this ?
I have to animate this shape base on user response. Thank you.
Use an ObjectAnimator to change the variables you use in onDraw. Below is an example of how you could implement this.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TrapezoidView trapezoidView = findViewById(R.id.trapezoid);
final Button resetButton = findViewById(R.id.btn_reset);
resetButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
trapezoidView.reset();
}
});
final Button animateButton = findViewById(R.id.btn_animate);
animateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
animateButton.setEnabled(false);
resetButton.setEnabled(false);
trapezoidView.toNewState();
}
});
trapezoidView.setListener(new TrapezoidView.TrapezoidListener() {
#Override
public void onNewState() {
animateButton.setEnabled(true);
resetButton.setEnabled(true);
}
});
}
}
TrapezoidView.java
public class TrapezoidView extends View {
public interface TrapezoidListener {
void onNewState();
}
public static final int TRAPEZOID_STATE = 0;
public static final int RECTANGLE_STATE = 1;
public static final int LINE_STATE = 2;
private int mState = TRAPEZOID_STATE;
private Paint mTrapezoidPaint;
private Path mTrapezoidPath = new Path();
private int mAnimationDuration = 5000; // 5 s in millis
private float mRectangleHeight = dpTopx(200);
private float mAltitude = mRectangleHeight;
private TrapezoidListener mListener;
public TrapezoidView(Context context, AttributeSet attrs) {
super(context, attrs);
mTrapezoidPaint = new Paint();
mTrapezoidPaint.setColor(Color.BLACK);
mTrapezoidPaint.setStrokeWidth(5.0f);
mTrapezoidPaint.setStyle(Paint.Style.STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTrapezoidPath.reset();
if (mState == TRAPEZOID_STATE) {
mAltitude = getHeight();
}
mTrapezoidPath.moveTo(0, 0);
mTrapezoidPath.lineTo(getWidth(), 0);
if (mState == LINE_STATE) {
mTrapezoidPath.lineTo(getWidth(), mAltitude);
mTrapezoidPath.lineTo(0, mAltitude);
} else {
mTrapezoidPath.lineTo(getWidth(), mRectangleHeight);
mTrapezoidPath.lineTo(0, mAltitude);
}
mTrapezoidPath.lineTo(0, 0);
mTrapezoidPath.close();
canvas.drawPath(mTrapezoidPath, mTrapezoidPaint);
}
private float dpTopx(int dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
public float getAltitude() {
return mAltitude;
}
public void setAltitude(float altitude) {
this.mAltitude = altitude;
invalidate();
}
public void reset() {
mState = TRAPEZOID_STATE;
mRectangleHeight = dpTopx(200);
mAltitude = mRectangleHeight;
invalidate();
}
public void setListener(TrapezoidListener listener) {
mListener = listener;
}
public void toNewState() {
if (mState == LINE_STATE) {
mListener.onNewState();
return;
}
float start;
float target;
final int targetState = mState == TRAPEZOID_STATE ? RECTANGLE_STATE : LINE_STATE;
if (targetState == RECTANGLE_STATE) {
start = getHeight();
target = mRectangleHeight;
} else {
start = mAltitude;
target = 0.0f;
}
ObjectAnimator stateAnimation = ObjectAnimator.ofFloat(TrapezoidView.this, "Altitude", start);
stateAnimation.setFloatValues(target);
stateAnimation.setDuration(mAnimationDuration);
stateAnimation.addListener(
new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
mState = targetState;
}
#Override
public void onAnimationEnd(Animator animation) {
mListener.onNewState();
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
}
);
stateAnimation.start();
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="50dp"
tools:context="test.example.MainActivity">
<test.example.TrapezoidView
android:id="#+id/trapezoid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.9" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.1"
android:orientation="horizontal">
<Button
android:id="#+id/btn_animate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Animate!" />
<Button
android:id="#+id/btn_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reset" />
</LinearLayout>
</LinearLayout>
I was developing user "eluleci" (https://gist.github.com/eluleci/6e0d02c766b27f6a5253) code
it's rippleTuch for preLilop
ok , it's extend Button class for do it,
when we have one button in our layout, all things work good and animation work smooth,
but when we add more than one button , like 5 button, by touch them the animation on the buttons get lag and not smooth!!
I cant understand what's the problem? Memory issues? and how can I fix it?can anyone knew where is the problem?
thank you for your attention
here is my code:
public class MehDiRippleButton extends Button {
#Override
public boolean isInEditMode() {
return true;
}
Paint paint=new Paint();
private static final int AnimDuration = 9000;
private TouchEffectAnimator touchEffectAnimator;
public MehDiRippleButton(Context context) {
super(context);
init();
}
public MehDiRippleButton(Context context, AttributeSet attrs) {
super(context, attrs);
allocated_TuchEffectAnimator();
TypedArray typedArray_MehDi_rippleButton_style = context.obtainStyledAttributes(attrs,R.styleable.MehDi_rippleButton_style);
CharSequence charSequence_buttonColor =typedArray_MehDi_rippleButton_style.getString(R.styleable.MehDi_rippleButton_style_MehDi_buttonColor);
paint.setColor(Color.parseColor(charSequence_buttonColor.toString()));
touchEffectAnimator.setStroke(paint);
CharSequence charSequence_rippleColor =typedArray_MehDi_rippleButton_style.getString(R.styleable.MehDi_rippleButton_style_MehDi_rippleColor);
if(charSequence_rippleColor!=null) {
touchEffectAnimator.setEffectColor(Color.parseColor(charSequence_rippleColor.toString()),Color.parseColor(charSequence_buttonColor.toString()));
}else touchEffectAnimator.setEffectColor(Color.LTGRAY,Color.WHITE);
typedArray_MehDi_rippleButton_style.recycle();
init();
}
private void allocated_TuchEffectAnimator(){
touchEffectAnimator = new TouchEffectAnimator(this);
}
private void init() {
touchEffectAnimator.setHasRippleEffect(true);
touchEffectAnimator.setAnimDuration(AnimDuration);
touchEffectAnimator.setClipRadius(0);
setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
}
});
}
#Override
public boolean onTouchEvent(final MotionEvent event) {
touchEffectAnimator.onTouchEvent(event);
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas canvas) {
touchEffectAnimator.onDraw(canvas);
super.onDraw(canvas);
}
}
and :
(in this class occurred the problem):
public class TouchEffectAnimator {
float u=0;
private static final int fadeout_time_helper=29;
private static final int tuchUp_time_helper=14;
private final int EASE_ANIM_DURATION = 2000;
private final int RIPPLE_ANIM_DURATION = 3000;
private final int MAX_RIPPLE_ALPHA = 255;
private View mView;
private int mClipRadius;
private boolean hasRippleEffect = false;
private int animDuration = EASE_ANIM_DURATION;
private int requiredRadius;
private float mDownX;
private float mDownY;
private float mRadius;
private int mCircleAlpha = MAX_RIPPLE_ALPHA;
private int mRectAlpha = 0;
private Paint mCirclePaint = new Paint();
private Paint mStrokePaint = new Paint();
private Paint mRectPaint = new Paint();
private Path mCirclePath = new Path();
private Path mRectPath = new Path();
private boolean isTouchReleased = false;
private boolean isAnimatingFadeIn = false;
/**
*
*
* */
private Animation.AnimationListener animationListener = new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
isAnimatingFadeIn = true;
}
#Override
public void onAnimationEnd(Animation animation) {
isAnimatingFadeIn = false;
if (isTouchReleased){
setStroke(mStrokePaint);
fadeOutEffect();
}
}
#Override
public void onAnimationRepeat(Animation animation) {
}
};
public TouchEffectAnimator(View mView) {
this.mView = mView;
}
public void setHasRippleEffect(boolean hasRippleEffect) {
this.hasRippleEffect = hasRippleEffect;
if (hasRippleEffect) animDuration = RIPPLE_ANIM_DURATION;
}
public void setAnimDuration(int animDuration) {
this.animDuration = animDuration;
}
public void setEffectColor(int effectColor,int buttonColor) {
mCirclePaint.setColor(effectColor);
mCirclePaint.setAlpha(mCircleAlpha);
mRectPaint.setColor(effectColor);
mRectPaint.setAlpha(mRectAlpha);
mStrokePaint.setColor(buttonColor);
}
public void setClipRadius(int mClipRadius) {
this.mClipRadius = mClipRadius;
}
public void onTouchEvent(final MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
isTouchReleased = true;
Drawable background = mView.getBackground();
if (background instanceof ShapeDrawable) {
((ShapeDrawable)background).getPaint().setStrokeWidth(0);
Log.e("fdsfsfd","fdsfdsfdsf");
} else if (background instanceof GradientDrawable) {
//((GradientDrawable)background).setS
Log.e("qqq","qqq");
}
ValueGeneratorAnim valueGeneratorAnim = new ValueGeneratorAnim(new InterpolatedTimeCallback() {
#Override
public void onTimeUpdate(float interpolatedTime) {
if (hasRippleEffect)
mRadius = requiredRadius * interpolatedTime +u;
mRectAlpha = (int) (interpolatedTime * MAX_RIPPLE_ALPHA);
mView.invalidate();
}
});
valueGeneratorAnim.setInterpolator(new DecelerateInterpolator());
valueGeneratorAnim.setDuration(animDuration/tuchUp_time_helper);
valueGeneratorAnim.setAnimationListener(animationListener);
mView.startAnimation(valueGeneratorAnim);
if (!isAnimatingFadeIn) {
setStroke(mStrokePaint);
fadeOutEffect();
}
} else if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
// gets the bigger value (width or height) to fit the circle
requiredRadius = mView.getWidth() >= mView.getHeight() ? mView.getWidth() : mView.getHeight();
final int requiredRadius2 = mView.getWidth() < mView.getHeight() ? mView.getWidth() : mView.getHeight();
noStroke(mStrokePaint);
requiredRadius *= 1.2;
Log.e("req ", "" + requiredRadius);
isTouchReleased = false;
mDownX = event.getX();
mDownY = mView.getMeasuredHeight()/2;
Drawable background = mView.getBackground();
if (background instanceof ShapeDrawable) {
((ShapeDrawable)background).getPaint().setStrokeWidth(0);
Log.e("fdsfsfd","fdsfdsfdsf");
} else if (background instanceof GradientDrawable) {
//((GradientDrawable)background).setS
Log.e("qqq","qqq");
}
mCircleAlpha = MAX_RIPPLE_ALPHA;
mRectAlpha = 0;
ValueGeneratorAnim valueGeneratorAnim = new ValueGeneratorAnim(new InterpolatedTimeCallback() {
#Override
public void onTimeUpdate(float interpolatedTime) {
Log.e("1 ", "" + 1);
if (hasRippleEffect)
mRadius = requiredRadius * interpolatedTime+(float)(requiredRadius2/1.5);
u=mRadius;
Log.e("mRa ", "" + mRadius);
Log.e("int ", "" + interpolatedTime);
mRectAlpha = (int) (interpolatedTime * MAX_RIPPLE_ALPHA);
mView.invalidate();
}
});
Log.e("222 ", "" + 222);
valueGeneratorAnim.setInterpolator(new DecelerateInterpolator());
valueGeneratorAnim.setDuration(animDuration);
valueGeneratorAnim.setAnimationListener(animationListener);
mView.startAnimation(valueGeneratorAnim);
}
}
public void onDraw(final Canvas canvas) {
if (hasRippleEffect) {
mCirclePath.reset();
mCirclePaint.setAlpha(mCircleAlpha);
mCirclePath.addRoundRect(new RectF(0, 0, mView.getWidth(), mView.getHeight()),
mClipRadius, mClipRadius, Path.Direction.CW);
canvas.clipPath(mCirclePath);
canvas.drawCircle(mDownX, mDownY, mRadius, mCirclePaint);
}
mRectPath.reset();
if (hasRippleEffect && mCircleAlpha != 255) mRectAlpha = mCircleAlpha / 2;
mRectPaint.setAlpha(mRectAlpha);
canvas.drawRoundRect(new RectF(0, 0, mView.getWidth(), mView.getHeight()), mClipRadius,mClipRadius, mRectPaint);
}
private void fadeOutEffect() {
ValueGeneratorAnim valueGeneratorAnim = new ValueGeneratorAnim(new InterpolatedTimeCallback() {
#Override
public void onTimeUpdate(float interpolatedTime) {
mCircleAlpha = (int) (MAX_RIPPLE_ALPHA - (MAX_RIPPLE_ALPHA * interpolatedTime));
mRectAlpha = mCircleAlpha;
mView.invalidate();
}
});
valueGeneratorAnim.setDuration(animDuration / fadeout_time_helper); /**change anim fade out time*/
mView.startAnimation(valueGeneratorAnim);
}
class ValueGeneratorAnim extends Animation {
private InterpolatedTimeCallback interpolatedTimeCallback;
ValueGeneratorAnim(InterpolatedTimeCallback interpolatedTimeCallback) {
this.interpolatedTimeCallback = interpolatedTimeCallback;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
this.interpolatedTimeCallback.onTimeUpdate(interpolatedTime);
}
}
interface InterpolatedTimeCallback {
public void onTimeUpdate(float interpolatedTime);
}
public void setStroke(Paint mStrokePaint){
GradientDrawable gradiant_withStroke = new GradientDrawable();
gradiant_withStroke.setColor(mStrokePaint.getColor());
gradiant_withStroke.setStroke(8, Color.parseColor("#00000000"));
mView.setBackgroundDrawable(gradiant_withStroke);
}
public void noStroke(Paint mStrokePaint){
GradientDrawable gradiant_withStroke = new GradientDrawable();
gradiant_withStroke.setColor(mStrokePaint.getColor());
gradiant_withStroke.setStroke(0, Color.parseColor("#00000000"));
mView.setBackgroundDrawable(gradiant_withStroke);
}
}
and activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical">
<com.example.mahdi.myapplication.MehDiRippleButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/view2"
android:layout_gravity="center_horizontal"
android:text="Ripple Tuch"
app:MehDi_rippleColor="#cf030a"
app:MehDi_buttonColor="#ff2c25"
/>
<com.example.mahdi.myapplication.MehDiRippleButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/view34"
android:text="Produce By"
app:MehDi_rippleColor="#f7f336"
app:MehDi_buttonColor="#d3ce00"
/>
<com.example.mahdi.myapplication.MehDiRippleButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/view"
android:layout_gravity="center_horizontal"
android:text="MehDi"
app:MehDi_rippleColor="#00930e"
app:MehDi_buttonColor="#00b909"
/>
<com.example.mahdi.myapplication.MehDiRippleButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/view3"
android:layout_gravity="center_horizontal"
android:text="NazaRi"
app:MehDi_rippleColor="#303dd3"
app:MehDi_buttonColor="#7688e5"
/>
<com.example.mahdi.myapplication.MehDiRippleButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/view23"
android:layout_gravity="center_horizontal"
android:text="؛)"
app:MehDi_rippleColor="#cf0584"
app:MehDi_buttonColor="#ff0fb6"
/>
<com.example.mahdi.myapplication.MehDiRippleButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/viehw23"
android:layout_gravity="center_horizontal"
android:text=":D"
app:MehDi_rippleColor="#a2a3a2"
app:MehDi_buttonColor="#dadbda"
/>
You need to dig out the Handler which executes most of these animation calls, and invoke handler.removeCallbacksAndMessages(null); and that will take care of some of the lag.
Because most probably, when you finish and reenter the said activity, it works good and fast as when first ran. This can be caused by having alot of Threads or Handler messages that have ended their lifecycle but haven't been removed due to being dead.
Here is activity and with in this activity only created one custom view
public class MainActivity extends Activity {
MyCustomDrawableView myCustomDrawableView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myCustomDrawableView = new MyCustomDrawableView(this);
setContentView(R.layout.activity_main);
myCustomDrawableView = (MyCustomDrawableView)findViewById(R.id.hello);
}
public class MyCustomDrawableView extends View {
private ShapeDrawable myDrawable;
public MyCustomDrawableView(Context context) {
super(context);
int x = 10;
int y = 10;
int width = 100;
int height = 100;
myDrawable = new ShapeDrawable(new OvalShape());
myDrawable.getPaint().setColor(0xff74fA23);
myDrawable.setBounds(x, y, x + width, y + height);
}
protected void onDraw(Canvas canvas) {
myDrawable.draw(canvas);
}
}
}
then in layout create customview as follows
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.mobiloitte.sampleapp.MainActivity.MyCustomDrawableView
android:id="#+id/hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
here i'm getting class not found exception
10-20 13:00:33.594: E/AndroidRuntime(542): Caused by: java.lang.ClassNotFoundException: com.mobiloitte.sampleapp.MainActivity.MyCustomDrawableView
pls help
Better is to use separate class (should not be an inner class) for custom view.
For your current problem, try with
<com.mobiloitte.sampleapp.MainActivity$MyCustomDrawableView
Update for current issue android.view.InflateException
You need to add one more constructor for your custom view
public MyCustomDrawableView(Context context, AttributeSet st) {
super(context, st);
// Do other initial tasks, like you did into MyCustomDrawableView(Context context).
}
This is my MainActivity:
public class MainActivity extends Activity {
PieMenu pieMenu;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pieMenu = new PieMenu(getApplicationContext());
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
{
pieMenu.addPieMenu(x,y);
}
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
}
return false;
}
}
PieMenu:
public class PieMenu extends FrameLayout{
private Context _context;
public PieMenu(Context context) {
super(context);
_context = context;
// TODO Auto-generated constructor stub
}
public void addPieMenu(int x, int y){
Toast.makeText(_context, "text",Toast.LENGTH_LONG).show();
PieItem pieView = new PieItem(_context,x,y,2);
//FrameLayout.LayoutParams lyp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
//pieView.setLayoutParams(lyp);
addView(pieView);
invalidate();
}
}
PieItem.java:
public class PieItem extends View{
private final float x;
private final float y;
private final int r;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public PieItem(Context context, float x, float y, int r) {
super(context);
mPaint.setColor(0xFFFF0000);
this.x = x;
this.y = y;
this.r = r;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(x, y, r, mPaint);
}
}
MainActivity.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="#string/hello_world" />
</FrameLayout>
Everytime I touch the scree, the toast is being called but the circle isn't being instantiated. Where am I going wrong?
easiest way to fix this, add view in onCreate:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pieMenu = new PieMenu(getApplicationContext());
FrameLayout fl = (FrameLayout)findViewById(R.id.layout);
fl.addView(pieMenu);
}
and add id to your main activity xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
You aren't adding pieMenu to any of the views in your layout (R.layout.activity_main)
What does your activity_main.xml look like?
You didn't add created PieMenu to activity layout. You need to call something like this in onCreate method:
view.addView(pieMenu);
Or add your PieMenu to you activity_main layout.
I'm trying the (surely simple?) task of having a TextView follow the thumb on a progress bar and show the progress in the TextView.
The problem is that for progress values of less than half max, the TextView drifts to the left of the thumb, getting more and more left of the correct place and vice versa with progress values more than half max the TextView drifts more and more to the right.
Below is a version of code that reproduces the problem...
Layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".Seekbar_test" >
<SeekBar
android:id="#+id/seekBar1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="59"
android:layout_marginTop="24dp" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge" />
And .java
package com.example.seekbar_test;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class Seekbar_test extends Activity {
SeekBar fade_seek;
TextView fade_text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_seekbar_test);
fade_seek = (SeekBar) findViewById(R.id.seekBar1);
fade_text = (TextView) findViewById(R.id.textView1);
fade_seek.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {
say_minutes_left(progress);
}
});
}
private void say_minutes_left(int how_many)
{
String what_to_say = String.valueOf(how_many);
fade_text.setText(what_to_say);
int seek_label_pos = (int)((float)(fade_seek.getMeasuredWidth()) * ((float)how_many / 60f));
fade_text.setX(seek_label_pos);
}
}
This works for me:
private void say_minutes_left(int how_many)
{
String what_to_say = String.valueOf(how_many);
fade_text.setText(what_to_say);
int seek_label_pos = (((fade_seek.getRight() - fade_seek.getLeft()) * fade_seek.getProgress()) / fade_seek.getMax()) + fade_seek.getLeft();
if (how_many <=9)
{
fade_text.setX(seek_label_pos - 6);
}
else
{
fade_text.setX(seek_label_pos - 11);
}
}
Thanks to Pushpendra Kuntal & flightplanner # unable to get right position of texBox in Thumb of seekbar
The following solution works for API >= 15:
Override SeekBar to create the getThumb() method that is not available on api 15:
public class CustomSeekBar extends SeekBar {
private Drawable thumb;
public CustomSeekBar(Context context) {
super(context);
}
public CustomSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void setThumb(Drawable thumb) {
super.setThumb(thumb);
this.thumb = thumb;
}
#Override
public Drawable getThumb() {
return thumb;
}
}
And use it Like this:
correctX = customSeekBar.getThumb().getBounds().left;
//Get the thumb bound and get its left value
int x = seekBar.getThumb().getBounds().left;
//set the left value to textview x value
textView.setX(x);
use this to move text view according to progress
Works good with Ken Nichols code, but here is a better decision, for example, to center you TextView to current position in ProgressBar(SeekBar):
private void say_minutes_left(int how_many)
{
String what_to_say = String.valueOf(how_many);
fade_text.setText(what_to_say);
int seek_label_pos = (((fade_seek.getRight() - fade_seek.getLeft()) * fade_seek.getProgress()) / fade_seek.getMax()) + fade_seek.getLeft();
fade_text.setX(seek_label_pos - fade_text.getWidth() / 2);
}
If you have padding in your ProgressBar(SeekBar), you can use more general version of this code:
private void say_minutes_left(int how_many)
{
String what_to_say = String.valueOf(how_many);
fade_text.setText(what_to_say);
int left = fade_seek.getLeft() + fade_seek.getPaddingLeft();
int right = fade_seek.getRight() - fade_seek.getPaddingRight();
int seek_label_pos = (((right - left * fade_seek.getProgress()) / fade_seek.getMax()) + left;
fade_text.setX(seek_label_pos - fade_text.getWidth() / 2);
}
Use this , we are calculating the x position based on progress and setting it to textview
seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
var xPosition= (((seekBar1.right - seekBar1.left) / seekBar1.max) * seekBar1.progress ) + seekBar1.left
textView1.translationX = xPosition.toFloat() - (textView1.width/2)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
TextView must be
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge"
/>
and remove it:
int seek_label_pos = (int)((float)(fade_seek.getMeasuredWidth()) * ((float)how_many / 60f));
fade_text.setX(seek_label_pos);
Hope it's help.