I made a custom view that is has 12 circles along a circular path. I would like to implement an onClick listener for each circle. How would I implement that in my custom view? I have also uploaded my code for the custom view. It just extends a View.
public class WatchView extends View {
private Paint mCircleTickPaint;
private Paint mHourPaint;
private Paint mMinutePaint;
private Paint mSecondPaint;
private boolean mShouldTick;
private int mTickSize;
private int mHourColor;
private int mMinuteColor;
private int mSecondColor;
private int mSeconds = 0;
private int mMinutes = 0;
private int mHours = 0;
private Handler handler = new Handler(Looper.getMainLooper());
public WatchView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.watchface,
0, 0);
try {
mShouldTick = a.getBoolean(R.styleable.watchface_shouldTick, true);
mTickSize = a.getInt(R.styleable.watchface_tickSize, 40);
mHourColor = a.getColor(R.styleable.watchface_hourColor, Color.RED);
mMinuteColor = a.getColor(R.styleable.watchface_minuteColor, Color.GREEN);
mSecondColor = a.getColor(R.styleable.watchface_secondColor, Color.BLUE);
} finally {
a.recycle();
}
init();
}
public void init() {
mCircleTickPaint = new Paint();
mCircleTickPaint.setAntiAlias(true);
mCircleTickPaint.setColor(Color.WHITE);
mHourPaint = new Paint();
mHourPaint.setAntiAlias(true);
mHourPaint.setColor(mHourColor);
mMinutePaint = new Paint();
mMinutePaint.setAntiAlias(true);
mMinutePaint.setColor(mMinuteColor);
mSecondPaint = new Paint();
mSecondPaint.setAntiAlias(true);
mSecondPaint.setColor(mSecondColor);
long now = System.currentTimeMillis();
SimpleDateFormat hh = new SimpleDateFormat("hh");
SimpleDateFormat mm = new SimpleDateFormat("mm");
SimpleDateFormat ss = new SimpleDateFormat("ss");
int hours = Integer.parseInt(hh.format(new Date(now)));
int minutes = Integer.parseInt(mm.format(new Date(now)));
int seconds = Integer.parseInt(ss.format(new Date(now)));
int mappedMinutes = (int) Utils.map(minutes, 1, 60, 1, 12);
int reverseSeconds = (60 - seconds) % 12;
int mappedSeconds = (int) Utils.map(reverseSeconds, 1, 60, 1, 12);
this.mHours = hours;
this.mMinutes = mappedMinutes;
this.mSeconds = mappedSeconds;
if (mShouldTick) {
if (null != handler) {
handler.removeCallbacks(mUpdateRunnable);
}
handler.post(mUpdateRunnable);
}
Log.d("WatchView", "Setting the time at: " + mHours + ":" + mMinutes + ":" + mSeconds);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centerX = canvas.getWidth() / 2;
int centerY = canvas.getHeight() / 2;
float innerTickRadius = centerX / 2;
for (int tickIndex = 0; tickIndex < 12; tickIndex++) {
float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
float innerX = (float) Math.sin(tickRot) * innerTickRadius;
float innerY = (float) -Math.cos(tickRot) * innerTickRadius;
int reverseSeconds = (60 - mSeconds) % 12;
int mappedSeconds = (int) Utils.map(reverseSeconds, 0, 11, 11, 0);
if (mHours == tickIndex) {
canvas.drawCircle(innerX + centerX, innerY + centerY, mTickSize, mHourPaint);
} else if (mMinutes == tickIndex) {
canvas.drawCircle(innerX + centerX, innerY + centerY, mTickSize, mMinutePaint);
} else if (mappedSeconds == tickIndex) {
canvas.drawCircle(innerX + centerX, innerY + centerY, mTickSize, mSecondPaint);
} else {
canvas.drawCircle(innerX + centerX, innerY + centerY, mTickSize, mCircleTickPaint);
}
}
}
private Runnable mUpdateRunnable = new Runnable() {
#Override public void run() {
mSeconds += 1;
if (mSeconds > 59) {
mSeconds = 0;
mMinutes += 1;
}
if (mMinutes > 59) {
mMinutes = 0;
mHours += 1;
}
if (mHours > 11) {
mHours = 0;
}
invalidate();
handler.postDelayed(mUpdateRunnable, 1000);
}
};
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int intrinsicSize = ScreenUtils.getScreenWidth(getContext());
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
width = Math.min(intrinsicSize, widthSize);
} else {
width = intrinsicSize;
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(intrinsicSize, heightSize);
} else {
height = intrinsicSize;
}
int min = Math.min(width, height);
setMeasuredDimension(min, min);
}
}
Related
Hi i have created custom view "Number Bar" which is working fine. I just want to add labels on each indicator. I tried that but when i draw text it is not visible because view is not getting height for that. Please check image below thanks.
View onDraw Source Code
protected void onDraw(Canvas canvas) {
int indicatorWidthHeight = Utils.dpToPx(getContext(), indicatorSize);
indicatorRadius = indicatorWidthHeight / 2;
int cx = indicatorWidthHeight / 2;
int cy = indicatorWidthHeight / 2;
int totalIndicators = 5;
int totalLines = totalIndicators - 1;
int lineWidth = (getMeasuredWidth() - (indicatorWidthHeight * totalIndicators)) / totalLines;
linePaint.setStrokeWidth(Utils.dpToPx(getContext(), lineHeight));
for (int i = 0; i < circles.length; i++) {
if (selected >= i) {
indicatorPaint.setColor(selectedBackgroundColor);
textPaint.setColor(selectedTextColor);
} else {
indicatorPaint.setColor(backgroundColor);
textPaint.setColor(textColor);
}
if (selected >= i + 1) {
linePaint.setColor(selectedBackgroundColor);
} else {
linePaint.setColor(backgroundColor);
}
int nCx = cx + (lineWidth + indicatorRadius * 2) * i;
circles[i].setRadius(indicatorRadius);
circles[i].setX(nCx);
circles[i].setY(cy);
canvas.drawCircle(nCx, cy, indicatorRadius, indicatorPaint);
String text = "" + (i+1);
textPaint.getTextBounds(text, 0, text.length(), rect);
canvas.drawText(text, nCx, cy+rect.height()/2, textPaint);
// Draw lines one less than circles
if (i != circles.length - 1) {
int startX = nCx + indicatorRadius;
int stopX = nCx + indicatorRadius + lineWidth;
lines[i].setStartX(startX);
lines[i].setStartY(cy);
lines[i].setStopX(stopX);
lines[i].setStopY(cy);
canvas.drawLine(startX, cy, stopX, cy, linePaint);
}
}
}
View Full Source Code
public class NumberBar extends View {
public static final int DEFAULT_TEXT_SIZE = 16;
public static final int DEF_INDICATOR_SIZE = 20;
Rect rect = new Rect();
Circle[] circles = new Circle[5];
Line[] lines = new Line[4];
private int backgroundColor, textColor, selectedBackgroundColor, selectedTextColor, indicatorSize, lineHeight, selected;
private Paint indicatorPaint;
private Paint textPaint;
private Paint linePaint;
private int indicatorRadius;
private boolean enabled = true;
public NumberBar(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NumberBar, 0, 0);
try {
backgroundColor = typedArray.getInteger(R.styleable.NumberBar_backgroundColor, Color.parseColor("#eeeeee"));
selectedBackgroundColor = typedArray.getInteger(R.styleable.NumberBar_selectedBackgroundColor, Color.parseColor("#0171fe"));
textColor = typedArray.getInteger(R.styleable.NumberBar_textColor, Color.parseColor("#c8c8c8"));
selectedTextColor = typedArray.getInteger(R.styleable.NumberBar_selectedTextColor, Color.parseColor("#ffffff"));
indicatorSize = typedArray.getInteger(R.styleable.NumberBar_indicatorSize, DEF_INDICATOR_SIZE);
lineHeight = typedArray.getInteger(R.styleable.NumberBar_lineHeight, 3);
selected = typedArray.getInteger(R.styleable.NumberBar_selected, 0);
enabled = typedArray.getBoolean(R.styleable.NumberBar_enabled, true);
} finally {
typedArray.recycle();
}
for (int i = 0; i < circles.length; i++) {
circles[i] = new Circle();
}
for (int i = 0; i < lines.length; i++) {
lines[i] = new Line();
}
indicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
indicatorPaint.setStyle(Paint.Style.FILL);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setTextSize(Utils.spToPx(getContext(), DEFAULT_TEXT_SIZE));
linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
linePaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
int indicatorWidthHeight = Utils.dpToPx(getContext(), indicatorSize);
indicatorRadius = indicatorWidthHeight / 2;
int cx = indicatorWidthHeight / 2;
int cy = indicatorWidthHeight / 2;
int totalIndicators = 5;
int totalLines = totalIndicators - 1;
int lineWidth = (getMeasuredWidth() - (indicatorWidthHeight * totalIndicators)) / totalLines;
linePaint.setStrokeWidth(Utils.dpToPx(getContext(), lineHeight));
for (int i = 0; i < circles.length; i++) {
if (selected >= i) {
indicatorPaint.setColor(selectedBackgroundColor);
textPaint.setColor(selectedTextColor);
} else {
indicatorPaint.setColor(backgroundColor);
textPaint.setColor(textColor);
}
if (selected >= i + 1) {
linePaint.setColor(selectedBackgroundColor);
} else {
linePaint.setColor(backgroundColor);
}
int nCx = cx + (lineWidth + indicatorRadius * 2) * i;
circles[i].setRadius(indicatorRadius);
circles[i].setX(nCx);
circles[i].setY(cy);
canvas.drawCircle(nCx, cy, indicatorRadius, indicatorPaint);
String text = "" + (i+1);
textPaint.getTextBounds(text, 0, text.length(), rect);
canvas.drawText(text, nCx, cy+rect.height()/2, textPaint);
// Draw lines one less than circles
if (i != circles.length - 1) {
int startX = nCx + indicatorRadius;
int stopX = nCx + indicatorRadius + lineWidth;
lines[i].setStartX(startX);
lines[i].setStartY(cy);
lines[i].setStopX(stopX);
lines[i].setStopY(cy);
canvas.drawLine(startX, cy, stopX, cy, linePaint);
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!enabled) {
return true;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
handleDownTouch(event.getX(), event.getY());
break;
}
return true;
}
private void handleDownTouch(float eventX, float eventY) {
for (int i = 0; i < circles.length; i++) {
if (isCircleClicked(eventX, eventY, circles[i])) { // Toast.makeText(NumberBar.this.getContext(), "Circle Clicked: " + i, Toast.LENGTH_SHORT).show();
this.selected = i;
invalidate();
return;
}
}
for (int i = 0; i < lines.length; i++) {
if (inLine(lines[i].getStartPoint(), lines[i].getStopPoint(), new Point((int)eventX, (int)eventY))) {
this.selected = i+1;
invalidate();
return; // Toast.makeText(NumberBar.this.getContext(), "Line: " + i, Toast.LENGTH_SHORT).show();
}
}
}
// is BC inline with AC or visa-versa
public boolean inLine(Point A, Point B, Point C) {
int offset = 5;
return C.x >= A.x && C.x <= B.x && (C.y <= (B.y-lineHeight+ offset) || C.y <= (B.y-lineHeight- offset));
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Don't measure width its most or which user will give
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int height;
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(indicatorSize, heightSize);
} else {
//Be whatever you want
height = indicatorSize;
}
//MUST CALL THIS
setMeasuredDimension(widthSize, height);
setMeasuredDimension(getMeasuredWidth(), Utils.dpToPx(getContext(), indicatorSize));
}
private boolean isCircleClicked(float ex, float ey, Circle circle) {
return Math.sqrt((circle.getX() - ex) * (circle.getX() - ex) + (circle.getY() - ey) * (circle.getY() - ey)) < circle.getRadius()+4;
}
public int getBackgroundColor() {
return backgroundColor;
}
#Override
public void setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
invalidate();
}
public int getTextColor() {
return textColor;
}
public void setTextColor(int textColor) {
this.textColor = textColor;
invalidate();
}
public int getSelectedBackgroundColor() {
return selectedBackgroundColor;
}
public void setSelectedBackgroundColor(int selectedBackgroundColor) {
this.selectedBackgroundColor = selectedBackgroundColor;
invalidate();
}
public int getSelectedTextColor() {
return selectedTextColor;
}
public void setSelectedTextColor(int selectedTextColor) {
this.selectedTextColor = selectedTextColor;
invalidate();
}
public int getIndicatorSize() {
return indicatorSize;
}
public void setIndicatorSize(int indicatorSize) {
this.indicatorSize = indicatorSize;
invalidate();
requestLayout();
}
public int getLineHeight() {
return lineHeight;
}
public void setLineHeight(int lineHeight) {
this.lineHeight = lineHeight;
invalidate();
requestLayout();
}
public int getSelected() {
return selected;
}
public void setSelected(int selected) {
this.selected = selected;
invalidate();
}
private class Circle {
int x, y;
int radius;
public Circle() {
}
public Circle(int x, int y, int radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
}
class Line {
Point startPoint = new Point();
Point stopPoint = new Point();
public int getStartX() {
return startPoint.x;
}
public void setStartX(int startX) {
this.startPoint.x = startX;
}
public int getStartY() {
return startPoint.y;
}
public void setStartY(int startY) {
this.startPoint.y = startY;
}
public int getStopX() {
return stopPoint.x;
}
public void setStopX(int stopX) {
this.stopPoint.x = stopX;
}
public int getStopY() {
return stopPoint.y;
}
public void setStopY(int stopY) {
this.stopPoint.y = stopY;
}
public Point getStartPoint() {
return startPoint;
}
public Point getStopPoint() {
return stopPoint;
}
}
#Override
public boolean isEnabled() {
return enabled;
}
#Override
public void setEnabled(boolean enabled) {
this.enabled = enabled;
} }
I am having a WaveFormView on which I want to change the color of it while playing Audio file and as the Audio is paused it should be stopped coloring at that certain point and when resumed it should continue forward with coloring. I am not getting how to do it in my code..
This is the screen shot of my generated waveform. Now when I will click on Play button it should change the color of waveform gradually with red color (from start to end slowly).
Here is my code to draw waveform view.
WaveFormView.class
public class WaveformView extends View {
public interface WaveformListener {
public void waveformFling(float x);
public void waveformDraw();
}
;
// Colors
private Paint mGridPaint;
private Paint mSelectedLinePaint;
private Paint mUnselectedLinePaint;
private Paint mUnselectedBkgndLinePaint;
private Paint mBorderLinePaint;
private Paint mPlaybackLinePaint;
private Paint mTimecodePaint;
private SoundFile mSoundFile;
private int[] mLenByZoomLevel;
private double[][] mValuesByZoomLevel;
private double[] mZoomFactorByZoomLevel;
private int[] mHeightsAtThisZoomLevel;
private int mZoomLevel;
private int mNumZoomLevels;
private int mSampleRate;
private int mSamplesPerFrame;
private int mOffset;
private int mSelectionStart;
private int mSelectionEnd;
private int mPlaybackPos;
private float mDensity;
private float mInitialScaleSpan;
private WaveformListener mListener;
private GestureDetector mGestureDetector;
private ScaleGestureDetector mScaleGestureDetector;
private boolean mInitialized;
Color color;
public WaveformView(Context context, AttributeSet attrs) {
super(context, attrs);
// We don't want keys, the markers get these
setFocusable(false);
mGridPaint = new Paint();
mGridPaint.setAntiAlias(false);
mGridPaint.setColor(
getResources().getColor(R.color.grid_line));
mSelectedLinePaint = new Paint();
mSelectedLinePaint.setAntiAlias(false);
mSelectedLinePaint.setColor(
getResources().getColor(R.color.waveform_selected));
mUnselectedLinePaint = new Paint();
mUnselectedLinePaint.setAntiAlias(false);
mUnselectedLinePaint.setColor(
getResources().getColor(R.color.waveform_unselected));
mUnselectedBkgndLinePaint = new Paint();
mUnselectedBkgndLinePaint.setAntiAlias(false);
mUnselectedBkgndLinePaint.setColor(
getResources().getColor(
R.color.selection_border));
mBorderLinePaint = new Paint();
mBorderLinePaint.setAntiAlias(true);
mBorderLinePaint.setStrokeWidth(1.5f);
mBorderLinePaint.setPathEffect(
new DashPathEffect(new float[]{3.0f, 2.0f}, 0.0f));
mBorderLinePaint.setColor(
getResources().getColor(R.color.selection_border));
mPlaybackLinePaint = new Paint();
mPlaybackLinePaint.setAntiAlias(false);
mPlaybackLinePaint.setColor(
getResources().getColor(R.color.playback_indicator));
mTimecodePaint = new Paint();
mTimecodePaint.setTextSize(12);
mTimecodePaint.setAntiAlias(true);
mTimecodePaint.setColor(
getResources().getColor(R.color.timecode));
mTimecodePaint.setShadowLayer(
2, 1, 1,
getResources().getColor(R.color.timecode_shadow));
mGestureDetector = new GestureDetector(
context,
new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(
MotionEvent e1, MotionEvent e2, float vx, float vy) {
mListener.waveformFling(vx);
return true;
}
});
mSoundFile = null;
mLenByZoomLevel = null;
mValuesByZoomLevel = null;
mHeightsAtThisZoomLevel = null;
mOffset = 0;
mPlaybackPos = -1;
mSelectionStart = 0;
mSelectionEnd = 0;
mDensity = 1.0f;
mInitialized = false;
}
public boolean hasSoundFile() {
return mSoundFile != null;
}
public void setSoundFile(SoundFile soundFile) {
mSoundFile = soundFile;
mSampleRate = mSoundFile.getSampleRate();
mSamplesPerFrame = mSoundFile.getSamplesPerFrame();
computeDoublesForAllZoomLevels();
mHeightsAtThisZoomLevel = null;
}
/**
* Called once when a new sound file is added
*/
private void computeDoublesForAllZoomLevels() {
int numFrames = mSoundFile.getNumFrames();
int[] frameGains = mSoundFile.getFrameGains();
double[] smoothedGains = new double[numFrames];
if (numFrames == 1) {
smoothedGains[0] = frameGains[0];
} else if (numFrames == 2) {
smoothedGains[0] = frameGains[0];
smoothedGains[1] = frameGains[1];
} else if (numFrames > 2) {
smoothedGains[0] = (double)(
(frameGains[0] / 2.0) +
(frameGains[1] / 2.0));
for (int i = 1; i < numFrames - 1; i++) {
smoothedGains[i] = (double)(
(frameGains[i - 1] / 3.0) +
(frameGains[i ] / 3.0) +
(frameGains[i + 1] / 3.0));
}
smoothedGains[numFrames - 1] = (double)(
(frameGains[numFrames - 2] / 2.0) +
(frameGains[numFrames - 1] / 2.0));
}
// Make sure the range is no more than 0 - 255
double maxGain = 1.0;
for (int i = 0; i < numFrames; i++) {
if (smoothedGains[i] > maxGain) {
maxGain = smoothedGains[i];
}
}
double scaleFactor = 1.0;
if (maxGain > 255.0) {
scaleFactor = 255 / maxGain;
}
// Build histogram of 256 bins and figure out the new scaled max
maxGain = 0;
int gainHist[] = new int[256];
for (int i = 0; i < numFrames; i++) {
int smoothedGain = (int)(smoothedGains[i] * scaleFactor);
if (smoothedGain < 0)
smoothedGain = 0;
if (smoothedGain > 255)
smoothedGain = 255;
if (smoothedGain > maxGain)
maxGain = smoothedGain;
gainHist[smoothedGain]++;
}
// Re-calibrate the min to be 5%
double minGain = 0;
int sum = 0;
while (minGain < 255 && sum < numFrames / 20) {
sum += gainHist[(int)minGain];
minGain++;
}
// Re-calibrate the max to be 99%
sum = 0;
while (maxGain > 2 && sum < numFrames / 100) {
sum += gainHist[(int)maxGain];
maxGain--;
}
// Compute the heights
double[] heights = new double[numFrames];
double range = maxGain - minGain;
for (int i = 0; i < numFrames; i++) {
double value = (smoothedGains[i] * scaleFactor - minGain) / range;
if (value < 0.0)
value = 0.0;
if (value > 1.0)
value = 1.0;
heights[i] = value * value;
}
mNumZoomLevels = 5;
mLenByZoomLevel = new int[5];
mZoomFactorByZoomLevel = new double[5];
mValuesByZoomLevel = new double[5][];
// Level 0 is doubled, with interpolated values
mLenByZoomLevel[0] = numFrames * 2;
mZoomFactorByZoomLevel[0] = 2.0;
mValuesByZoomLevel[0] = new double[mLenByZoomLevel[0]];
if (numFrames > 0) {
mValuesByZoomLevel[0][0] = 0.5 * heights[0];
mValuesByZoomLevel[0][1] = heights[0];
}
for (int i = 1; i < numFrames; i++) {
mValuesByZoomLevel[0][2 * i] = 0.5 * (heights[i - 1] + heights[i]);
mValuesByZoomLevel[0][2 * i + 1] = heights[i];
}
// Level 1 is normal
mLenByZoomLevel[1] = numFrames;
mValuesByZoomLevel[1] = new double[mLenByZoomLevel[1]];
mZoomFactorByZoomLevel[1] = 1.0;
for (int i = 0; i < mLenByZoomLevel[1]; i++) {
mValuesByZoomLevel[1][i] = heights[i];
}
// 3 more levels are each halved
for (int j = 2; j < 5; j++) {
mLenByZoomLevel[j] = mLenByZoomLevel[j - 1] / 2;
mValuesByZoomLevel[j] = new double[mLenByZoomLevel[j]];
mZoomFactorByZoomLevel[j] = mZoomFactorByZoomLevel[j - 1] / 2.0;
for (int i = 0; i < mLenByZoomLevel[j]; i++) {
mValuesByZoomLevel[j][i] =
0.5 * (mValuesByZoomLevel[j - 1][2 * i] +
mValuesByZoomLevel[j - 1][2 * i + 1]);
}
}
if (numFrames > 5000) {
mZoomLevel = 3;
} else if (numFrames > 1000) {
mZoomLevel = 2;
} else if (numFrames > 300) {
mZoomLevel = 1;
} else {
mZoomLevel = 0;
}
mInitialized = true;
}
public boolean canZoomIn() {
return (mZoomLevel > 0);
}
public void zoomIn() {
if (canZoomIn()) {
mZoomLevel--;
mSelectionStart *= 2;
mSelectionEnd *= 2;
mHeightsAtThisZoomLevel = null;
int offsetCenter = mOffset + getMeasuredWidth() / 2;
offsetCenter *= 2;
mOffset = offsetCenter - getMeasuredWidth() / 2;
if (mOffset < 0)
mOffset = 0;
invalidate();
}
}
public boolean canZoomOut() {
return (mZoomLevel < mNumZoomLevels - 1);
}
public void zoomOut() {
if (canZoomOut()) {
mZoomLevel++;
mSelectionStart /= 2;
mSelectionEnd /= 2;
int offsetCenter = mOffset + getMeasuredWidth() / 2;
offsetCenter /= 2;
mOffset = offsetCenter - getMeasuredWidth() / 2;
if (mOffset < 0)
mOffset = 0;
mHeightsAtThisZoomLevel = null;
invalidate();
}
}
public double pixelsToSeconds(int pixels) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (pixels * (double)mSamplesPerFrame / (mSampleRate * z));
}
public void setListener(WaveformListener listener) {
mListener = listener;
}
public void recomputeHeights(float density) {
mHeightsAtThisZoomLevel = null;
mDensity = density;
mTimecodePaint.setTextSize((int)(12 * density));
invalidate();
}
protected void drawWaveformLine(Canvas canvas,
int x, int y0, int y1,
Paint paint) {
canvas.drawLine(x, y0, x, y1, paint);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mSoundFile == null)
return;
if (mHeightsAtThisZoomLevel == null)
computeIntsForThisZoomLevel();
DisplayMetrics displaymetrics = getContext().getResources().getDisplayMetrics();
int height = displaymetrics.heightPixels;
int widths = displaymetrics.widthPixels;
// Draw waveform
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int start = mOffset;
int width = mHeightsAtThisZoomLevel.length - start;
int ctr = measuredHeight / 2;
Log.e("wid",String.valueOf(width));
Log.e("widCal",String.valueOf(mHeightsAtThisZoomLevel.length));
Log.e("widstart",String.valueOf(start));
if (width > measuredWidth)
width = measuredWidth;
Log.e("measured",String.valueOf(measuredWidth));
// Draw grid
double onePixelInSecs = pixelsToSeconds(1);
boolean onlyEveryFiveSecs = (onePixelInSecs > 1.0 / 50.0);
double fractionalSecs = mOffset * onePixelInSecs;
int integerSecs = (int) fractionalSecs;
int i = 0;
while (i < width) {
i++;
fractionalSecs += onePixelInSecs;
int integerSecsNew = (int) fractionalSecs;
if (integerSecsNew != integerSecs) {
integerSecs = integerSecsNew;
if (!onlyEveryFiveSecs || 0 == (integerSecs % 5)) {
canvas.drawLine(i, 0, i, measuredHeight, mGridPaint);
}
}
}
// Draw waveform
for ( i = 0; i < width; i++) {
Paint paint;
if (i + start >= mSelectionStart &&
i + start < mSelectionEnd) {
paint = mSelectedLinePaint;
// paint.setColor(color);
} else {
drawWaveformLine(canvas, ((widths/width)*i), 0, measuredHeight,
mUnselectedBkgndLinePaint);
paint = mUnselectedLinePaint;
}
drawWaveformLine(
canvas, ((widths/width)*i),
ctr - mHeightsAtThisZoomLevel[start + i],
ctr + 1 + mHeightsAtThisZoomLevel[start + i],
paint);
if (i + start == mPlaybackPos) {
canvas.drawLine(i, 0, i, measuredHeight, mPlaybackLinePaint);
}
}
if (mListener != null) {
mListener.waveformDraw();
}
}
private void computeIntsForThisZoomLevel() {
int halfHeight = (getMeasuredHeight() / 2) - 1;
mHeightsAtThisZoomLevel = new int[mLenByZoomLevel[mZoomLevel]];
for (int i = 0; i < mLenByZoomLevel[mZoomLevel]; i++) {
mHeightsAtThisZoomLevel[i] =
(int)(mValuesByZoomLevel[mZoomLevel][i] * halfHeight);
}
}
}
MainActivity.class
public class MainActivity extends AppCompatActivity implements WaveformView.WaveformListener {
WaveformView mWaveformView;
SoundFile mSoundFile;
private float mDensity;
private File mFile;
private String mFilename;
private long mLoadingLastUpdateTime;
boolean mLoadingKeepGoing;
boolean mFinishActivity;
private ProgressDialog mProgressDialog;
String mTitle,mArtist;
private Thread mLoadSoundFileThread;
private Thread mRecordAudioThread;
private Thread mSaveSoundFileThread;
private boolean mIsPlaying;
private SamplePlayer mPlayer;
private String mInfoContent;
private int mWidth;
private int mMaxPos;
private int mStartPos;
private int mEndPos;
private boolean mStartVisible;
private boolean mEndVisible;
private int mLastDisplayedStartPos;
private int mLastDisplayedEndPos;
private int mOffset;
private int mOffsetGoal;
private int mFlingVelocity;
private int mPlayStartMsec;
private int mPlayEndMsec;
private Handler mHandler;
Button pla;
MediaPlayer mediaPlayer;
boolean ismIsPlaying;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pla = (Button)findViewById(R.id.play);
mWaveformView = (WaveformView)findViewById(R.id.waveform);
mWaveformView.setListener(this);
mHandler = new Handler();
Uri uri = Uri.parse("/sdcard/audio_file.mp3");
mediaPlayer = new MediaPlayer();
mediaPlayer = MediaPlayer.create(getApplicationContext(),uri);
loadGui();
loadFromFile();
}
/**
* Called from both onCreate and onConfigurationChanged
* (if the user switched layouts)
*/
private void loadGui() {
// Inflate our UI from its XML layout description.
setContentView(R.layout.activity_main);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
mDensity = metrics.density;
mWaveformView = (WaveformView)findViewById(R.id.waveform);
mWaveformView.setListener(this);
if (mSoundFile != null && !mWaveformView.hasSoundFile()) {
mWaveformView.setSoundFile(mSoundFile);
mWaveformView.recomputeHeights(mDensity);
}
}
private void loadFromFile() {
mFilename = "/sdcard/audio_file.mp3";
mFile = new File(mFilename);
SongMetadataReader metadataReader = new SongMetadataReader(
this, mFilename);
mTitle = metadataReader.mTitle;
mArtist = metadataReader.mArtist;
String titleLabel = mTitle;
if (mArtist != null && mArtist.length() > 0) {
titleLabel += " - " + mArtist;
}
setTitle(titleLabel);
mLoadingLastUpdateTime = getCurrentTime();
mLoadingKeepGoing = true;
mFinishActivity = false;
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setTitle("Loading...");
mProgressDialog.setCancelable(true);
mProgressDialog.setOnCancelListener(
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
mLoadingKeepGoing = false;
mFinishActivity = true;
}
});
mProgressDialog.show();
final SoundFile.ProgressListener listener =
new SoundFile.ProgressListener() {
public boolean reportProgress(double fractionComplete) {
long now = getCurrentTime();
if (now - mLoadingLastUpdateTime > 100) {
mProgressDialog.setProgress(
(int) (mProgressDialog.getMax() * fractionComplete));
mLoadingLastUpdateTime = now;
}
return mLoadingKeepGoing;
}
};
// Load the sound file in a background thread
mLoadSoundFileThread = new Thread() {
public void run() {
try {
mSoundFile = SoundFile.create(mFile.getAbsolutePath(), listener);
if (mSoundFile == null) {
mProgressDialog.dismiss();
String name = mFile.getName().toLowerCase();
String[] components = name.split("\\.");
String err;
if (components.length < 2) {
err = getResources().getString(
R.string.no_extension_error);
} else {
err = getResources().getString(
R.string.bad_extension_error) + " " +
components[components.length - 1];
}
final String finalErr = err;
Runnable runnable = new Runnable() {
public void run() {
showFinalAlert(new Exception(), finalErr);
}
};
mHandler.post(runnable);
return;
}
mPlayer = new SamplePlayer(mSoundFile);
} catch (final Exception e) {
mProgressDialog.dismiss();
e.printStackTrace();
mInfoContent = e.toString();
runOnUiThread(new Runnable() {
public void run() {
}
});
Runnable runnable = new Runnable() {
public void run() {
showFinalAlert(e, getResources().getText(R.string.read_error));
}
};
mHandler.post(runnable);
return;
}
mProgressDialog.dismiss();
if (mLoadingKeepGoing) {
Runnable runnable = new Runnable() {
public void run() {
finishOpeningSoundFile();
}
};
mHandler.post(runnable);
} else if (mFinishActivity){
MainActivity.this.finish();
}
}
};
mLoadSoundFileThread.start();
}
private void finishOpeningSoundFile() {
mWaveformView.setSoundFile(mSoundFile);
mWaveformView.recomputeHeights(mDensity);
Log.e("sound file",mFilename);
Log.e("sound", String.valueOf(mSoundFile));
}
/**
* Show a "final" alert dialog that will exit the activity
* after the user clicks on the OK button. If an exception
* is passed, it's assumed to be an error condition, and the
* dialog is presented as an error, and the stack trace is
* logged. If there's no exception, it's a success message.
*/
private void showFinalAlert(Exception e, CharSequence message) {
CharSequence title;
if (e != null) {
Log.e("Ringdroid", "Error: " + message);
Log.e("Ringdroid", getStackTrace(e));
title = getResources().getText(R.string.alert_title_failure);
setResult(RESULT_CANCELED, new Intent());
} else {
Log.v("Ringdroid", "Success: " + message);
title = getResources().getText(R.string.alert_title_success);
}
new AlertDialog.Builder(MainActivity.this)
.setTitle(title)
.setMessage(message)
.setPositiveButton(
R.string.alert_ok_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
finish();
}
})
.setCancelable(false)
.show();
}
private void showFinalAlert(Exception e, int messageResourceId) {
showFinalAlert(e, getResources().getText(messageResourceId));
}
#Override
public void waveformTouchStart(float x) {
}
#Override
public void waveformTouchMove(float x) {
}
#Override
public void waveformTouchEnd() {
}
#Override
public void waveformFling(float x) {
}
#Override
public void waveformDraw() {
mWidth = mWaveformView.getMeasuredWidth();
if (mOffsetGoal != mOffset) {
// updateDisplay();
}
else if (mIsPlaying) {
// updateDisplay();
} else if (mFlingVelocity != 0) {
// updateDisplay();
}
}
private long getCurrentTime() {
return System.nanoTime() / 1000000;
}
private String getStackTrace(Exception e) {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
return writer.toString();
}
public void buttonClick(View view) {
Toast.makeText(MainActivity.this, "test", Toast.LENGTH_SHORT).show();
mediaPlayer.start();
ismIsPlaying = true;
}
}
In your onDraw(Canvas canvas) add the following lines
if (i + start <= mPlaybackPos) {
Paint mPaint = new Paint(paint);
mPaint.setColor(Color.RED);
drawWaveformLine(
canvas, ((widths/width)*i),
ctr - mHeightsAtThisZoomLevel[start + i],
ctr + 1 + mHeightsAtThisZoomLevel[start + i],
mPaint);
}
add them above the line:
if (i + start == mPlaybackPos) {
And if this works, consider to allocate the Paint-object outside the onDraw() method.
Em...the title is not clearly, here is my question: i custom a view to display calendar, my logic is when user swipe horizontal it can switch month of current year, when user swipe vertical it can switch year of current month, like image below:
Here is my all code below and i delete some useless code:
public class MonthView extends View {
private static final Region[][] MONTH_REGIONS = new Region[6][7];
private DPCManager mCManager = DPCManager.getInstance();
private DPTManager mTManager = DPTManager.getInstance();
private TextPaint mTextPaint;
private Paint mPaint;
private Scroller mScroller;
private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator();
private AccelerateInterpolator accelerateInterpolator = new AccelerateInterpolator();
private OnDateChangeListener onDateChangeListener;
private ScaleAnimationListener scaleAnimationListener = new ScaleAnimationListener();
private DPMode mode;
private int indexYear, indexMonth;
private int centerYear, centerMonth;
private int leftYear, leftMonth;
private int rightYear, rightMonth;
private int topYear, topMonth;
private int bottomYear, bottomMonth;
private int width, height;
private int lastHeight, nextHeight;
private int baseSize;
private int sizeDecor, sizeDecor2x, sizeDecor3x;
private int lastPointX, lastPointY;
private int lastMoveX, lastMoveY;
private int criticalWidth, criticalHeight;
private float sizeTextGregorian, sizeTextFestival;
private float offsetYFestival1, offsetYFestival2;
private boolean isSlideV;
private Map<String, BGCircle> circlesAppear = new HashMap<>();
private Map<String, BGCircle> circlesDisappear = new HashMap<>();
private List<String> dateSelected = new ArrayList<>();
public interface OnDateChangeListener {
void onMonthChange(int month);
void onYearChange(int year);
}
public MonthView(Context context) {
this(context, null);
}
public MonthView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
mTextPaint = new TextPaint();
mTextPaint.setTextAlign(Paint.Align.CENTER);
mPaint = new Paint();
}
void setOnDateChangeListener(OnDateChangeListener onDateChangeListener) {
this.onDateChangeListener = onDateChangeListener;
}
void setMode(DPMode mode) {
this.mode = mode;
}
void setDate(int year, int month) {
centerYear = year;
centerMonth = month;
indexYear = 0;
indexMonth = 0;
computeDate();
requestLayout();
invalidate();
}
private void computeDate() {
rightYear = leftYear = centerYear;
topYear = centerYear - 1;
bottomYear = centerYear + 1;
topMonth = centerMonth;
bottomMonth = centerMonth;
rightMonth = centerMonth + 1;
leftMonth = centerMonth - 1;
if (centerMonth == 12) {
rightYear++;
rightMonth = 1;
}
if (centerMonth == 1) {
leftYear--;
leftMonth = 12;
}
if (null != onDateChangeListener) {
onDateChangeListener.onYearChange(centerYear);
onDateChangeListener.onMonthChange(centerMonth);
}
}
#Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
} else {
}
}
boolean isNewEvent = false;
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isNewEvent = true;
lastPointX = (int) event.getX();
lastPointY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
if (isNewEvent) {
if (Math.abs(lastPointX - event.getX()) > 100) {
isSlideV = false;
isNewEvent = false;
} else if (Math.abs(lastPointY - event.getY()) > 50) {
isSlideV = true;
isNewEvent = false;
}
}
if (isSlideV) {
int totalMoveY = (int) (lastPointY - event.getY()) + lastMoveY;
smoothScrollTo(0, totalMoveY);
} else {
int totalMoveX = (int) (lastPointX - event.getX()) + lastMoveX;
smoothScrollTo(totalMoveX, 0);
}
break;
case MotionEvent.ACTION_UP:
if (isSlideV) {
if (Math.abs(lastPointY - event.getY()) > 25) {
if (lastPointY < event.getY()) {
if (Math.abs(lastPointY - event.getY()) >= criticalHeight) {
indexYear--;
centerYear = centerYear - 1;
computeDate();
}
smoothScrollTo(0, height * indexYear);
lastMoveY = height * indexYear;
} else if (lastPointY > event.getY()) {
if (Math.abs(lastPointY - event.getY()) >= criticalHeight) {
indexYear++;
centerYear = centerYear + 1;
computeDate();
}
smoothScrollTo(0, height * indexYear);
lastMoveY = height * indexYear;
}
} else {
}
} else {
if (Math.abs(lastPointX - event.getX()) > 25) {
if (lastPointX > event.getX()) {
if (Math.abs(lastPointX - event.getX()) >= criticalWidth) {
indexMonth++;
centerMonth = (centerMonth + 1) % 13;
if (centerMonth == 0) {
centerMonth = 1;
centerYear++;
}
computeDate();
}
smoothScrollTo(width * indexMonth, 0);
lastMoveX = width * indexMonth;
} else if (lastPointX < event.getX()) {
if (Math.abs(lastPointX - event.getX()) >= criticalWidth) {
indexMonth--;
centerMonth = (centerMonth - 1) % 12;
if (centerMonth == 0) {
centerMonth = 12;
centerYear--;
}
computeDate();
}
smoothScrollTo(width * indexMonth, 0);
lastMoveX = width * indexMonth;
}
} else {
}
}
break;
}
return true;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(measureWidth, measureWidth * 6 / 7F);
}
#Override
protected void onSizeChanged(int w, int h, int oldW, int oldH) {
width = w;
height = h;
criticalWidth = (int) (1F / 5F * width);
criticalHeight = (int) (1F / 5F * height);
baseSize = w;
int sizeCell = (int) (baseSize / 7F);
sizeDecor = (int) (sizeCell / 3F);
sizeDecor2x = sizeDecor * 2;
sizeDecor3x = sizeDecor * 3;
sizeTextGregorian = baseSize / 20F;
mTextPaint.setTextSize(sizeTextGregorian);
float heightGregorian = mTextPaint.getFontMetrics().bottom - mTextPaint.getFontMetrics().top;
sizeTextFestival = baseSize / 40F;
mTextPaint.setTextSize(sizeTextFestival);
float heightFestival = mTextPaint.getFontMetrics().bottom - mTextPaint.getFontMetrics().top;
offsetYFestival1 = (((Math.abs(mTextPaint.ascent() + mTextPaint.descent())) / 2F) +
heightFestival / 2F + heightGregorian / 2F) / 2F;
offsetYFestival2 = offsetYFestival1 * 2F;
for (int i = 0; i < MONTH_REGIONS.length; i++) {
for (int j = 0; j < MONTH_REGIONS[i].length; j++) {
Region region = new Region();
region.set((j * sizeCell), (i * sizeCell), sizeCell + (j * sizeCell),
sizeCell + (i * sizeCell));
MONTH_REGIONS[i][j] = region;
}
}
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.LTGRAY);
draw(canvas, width * (indexMonth - 1), height * indexYear, leftYear, leftMonth);
draw(canvas, width * indexMonth, height * indexYear, centerYear, centerMonth);
draw(canvas, width * (indexMonth + 1), height * indexYear, rightYear, rightMonth);
draw(canvas, width * indexMonth, height * (indexYear - 1), topYear, topMonth);
draw(canvas, width * indexMonth, height * (indexYear + 1), bottomYear, bottomMonth);
}
private void draw(Canvas canvas, int x, int y, int year, int month) {
canvas.save();
canvas.translate(x, y);
DPInfo[][] info = mCManager.obtainDPInfo(year, month);
for (int i = 0; i < info.length; i++) {
for (int j = 0; j < info[i].length; j++) {
draw(canvas, MONTH_REGIONS[i][j].getBounds(), info[i][j]);
}
}
canvas.restore();
}
private void draw(Canvas canvas, Rect rect, DPInfo info) {
drawGregorian(canvas, rect, info.strG, info.isWeekend);
}
private void drawGregorian(Canvas canvas, Rect rect, String str, boolean isWeekend) {
mTextPaint.setTextSize(sizeTextGregorian);
if (isWeekend) {
mTextPaint.setColor(mTManager.colorWeekend());
} else {
mTextPaint.setColor(mTManager.colorG());
}
canvas.drawText(str, rect.centerX(), rect.centerY(), mTextPaint);
}
private void smoothScrollTo(int fx, int fy) {
int dx = fx - mScroller.getFinalX();
int dy = fy - mScroller.getFinalY();
smoothScrollBy(dx, dy);
}
private void smoothScrollBy(int dx, int dy) {
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, 500);
invalidate();
}
}
If i swipe vertical to switch year, for example 2015/7-->2016/7-->2017/7, it's run correctly, but now if i swipe horizontal to switch month, for example 2017/7-->2017/6, everything will not display:
That's mean only horizontal and vertical on current month can touch and display correctly, for example the default display month is 2015/7, when i swipe to 2016/7 or 2017/7, i can't get the correct display when i swipe to 2017/6 or 2017/8, only swipe back to 2015/7 to swipe correctly can get the correct display of 2015/6 and 2015/8.
This problem troubled me many days, the coordinates and data of months all correct, i don't know why it happen, hope and thanks for your answer.
I want to move the seconds hand smoothly and swiftly as I have watched many watches moving their seconds hand swiftly with out making tick tick movements .
I have tried this code from open source and it is working fine
public class AnalogClock1 extends View {
public AnalogClock1(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
private Time mCalendar;
private Drawable mHourHand;
private Drawable mMinuteHand;
private Drawable mSecondHand;
private Drawable mDial;
private int mDialWidth;
private int mDialHeight;
private boolean mAttached;
private final Handler mHandler = new Handler();
private float mMinutes;
private float mHour;
private float mMillisec;
private boolean mChanged;
Context mContext;
public AnalogClock1(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AnalogClock1(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
Resources r = context.getResources();
TypedArray a =
context.obtainStyledAttributes(
attrs, R.styleable.AnalogClock, defStyle, 0);
mContext=context;
// mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial);
// if (mDial == null) {
mDial = r.getDrawable(R.drawable.clock_dial);
// }
// mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour);
// if (mHourHand == null) {
mHourHand = r.getDrawable(R.drawable.clock_hour);
// }
// mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute);
// if (mMinuteHand == null) {
mMinuteHand = r.getDrawable(R.drawable.clock_minute);
mSecondHand = r.getDrawable(R.drawable.clockgoog_minute);
// }
mCalendar = new Time();
mDialWidth = mDial.getIntrinsicWidth();
mDialHeight = mDial.getIntrinsicHeight();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);
}
// NOTE: It's safe to do these after registering the receiver since the receiver always runs
// in the main thread, therefore the receiver can't run before this method returns.
// The time zone may have changed while the receiver wasn't registered, so update the Time
mCalendar = new Time();
// Make sure we update to the current time
onTimeChanged();
counter.start();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAttached) {
counter.cancel();
getContext().unregisterReceiver(mIntentReceiver);
mAttached = false;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
float hScale = 1.0f;
float vScale = 1.0f;
if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
hScale = (float) widthSize / (float) mDialWidth;
}
if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
vScale = (float )heightSize / (float) mDialHeight;
}
float scale = Math.min(hScale, vScale);
setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec),
resolveSize((int) (mDialHeight * scale), heightMeasureSpec));
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mChanged = true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
boolean changed = mChanged;
if (changed) {
mChanged = false;
}
boolean seconds = mSeconds;
if (seconds ) {
mSeconds = false;
}
int availableWidth = 200;
int availableHeight = 200;
int x = availableWidth / 2;
int y = availableHeight / 2;
final Drawable dial = mDial;
int w = dial.getIntrinsicWidth();
int h = dial.getIntrinsicHeight();
boolean scaled = false;
if (availableWidth < w || availableHeight < h) {
scaled = true;
float scale = Math.min((float) availableWidth / (float) w,
(float) availableHeight / (float) h);
canvas.save();
canvas.scale(scale, scale, x, y);
}
if (changed) {
dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
dial.draw(canvas);
canvas.save();
canvas.rotate(mHour / 12.0f * 360.0f, x, y);
final Drawable hourHand = mHourHand;
if (changed) {
w = hourHand.getIntrinsicWidth();
h = hourHand.getIntrinsicHeight();
hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
hourHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mMinutes / 60.0f * 360.0f, x, y);
//canvas.rotate(mSecond, x, y);
final Drawable minuteHand = mMinuteHand;
if (changed) {
w = minuteHand.getIntrinsicWidth();
h = minuteHand.getIntrinsicHeight();
minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
minuteHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mSecond, x, y);
//minuteHand = mMinuteHand;
if (seconds) {
w = mSecondHand.getIntrinsicWidth();
h = mSecondHand.getIntrinsicHeight();
mSecondHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
mSecondHand.draw(canvas);
canvas.restore();
if (scaled) {
canvas.restore();
}
}
MyCount counter = new MyCount(10000, 1000);
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
counter.start();
}
#Override
public void onTick(long millisUntilFinished) {
mCalendar.setToNow();
int hour = mCalendar.hour;
int minute = mCalendar.minute;
int second = mCalendar.second;
mSecond=6.0f*second;
mSeconds=true;
//mChanged = true;
AnalogClock1.this.invalidate();
//Toast.makeText(mContext, "text", Toast.LENGTH_LONG).show();
}
}
boolean mSeconds=false;
float mSecond=0;
private void onTimeChanged() {
mCalendar.setToNow();
int hour = mCalendar.hour;
int minute = mCalendar.minute;
int second = mCalendar.second;
mMinutes = minute + second / 60.0f;
mHour = hour + mMinutes / 60.0f;
mChanged = true;
}
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
}
onTimeChanged();
invalidate();
}
};
}
Please help me out.
I think that you got to change the values that you are assigning to the Counter class.
in the particular case I think that you should really need to change the values in the Following line inside your code.
MyCount counter = new MyCount(10000, 1000);
please rate if this works.
I work at world analog clock I used android analog clock, it's work at activity but I can't use it at widget,I tired googled it is there any one have idea ?
You can use the following widget classes in Home Screen Widget:
* AnalogClock
* Button
* Chronometer
* ImageButton
* ImageView
* ProgressBar
* TextView
Descendants of these classes are not supported
see an example how we use an AnalogClock widget in Home Screen widget here
You have to create your own widget based on ImageView and create background service to create bitmaps and periodically push them to widget.
/**
*
* This widget display an analogic clock with two hands for hours and
*
* minutes.
*/
#RemoteView
public class AnalogClock2 extends View {
public AnalogClock2(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
private Time mCalendar;
private Drawable mHourHand;
private Drawable mMinuteHand;
private Drawable mSecondHand;
private Drawable mDial;
private int mDialWidth;
private int mDialHeight;
private boolean mAttached;
private final Handler mHandler = new Handler();
private float mMinutes;
private float mHour;
private boolean mChanged;
Context mContext;
public static String mtimezone="Asia/Calcutta";
public AnalogClock2(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AnalogClock2(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
Resources r = context.getResources();
// TypedArray a =
// context.obtainStyledAttributes(
// attrs, R.styleable.AnalogClock, defStyle, 0);
mContext = context;
// mDial =
// a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial);
// if (mDial == null) {
mDial = r.getDrawable(R.drawable.widgetdial);
// }
// mHourHand =
// a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour);
// if (mHourHand == null) {
mHourHand = r.getDrawable(R.drawable.widgethour);
// }
// mMinuteHand =
// a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute);
// if (mMinuteHand == null) {
mMinuteHand = r.getDrawable(R.drawable.widgetminute);
mSecondHand = r.getDrawable(R.drawable.widgetminute);
// }
mCalendar = new Time();
mDialWidth = mDial.getIntrinsicWidth();
mDialHeight = mDial.getIntrinsicHeight();
}
public static void timezone(String timezone){
mtimezone=timezone;
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);
}
// NOTE: It's safe to do these after registering the receiver since the
// receiver always runs
// in the main thread, therefore the receiver can't run before this
// method returns.
// The time zone may have changed while the receiver wasn't registered,
// so update the Time
//mCalendar = new Time();
mCalendar = new Time(mtimezone);
// Make sure we update to the current time
onTimeChanged();
counter.start();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAttached) {
counter.cancel();
getContext().unregisterReceiver(mIntentReceiver);
mAttached = false;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
float hScale = 1.0f;
float vScale = 1.0f;
if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
hScale = (float) widthSize / (float) mDialWidth;
}
if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
vScale = (float) heightSize / (float) mDialHeight;
}
System.out.println("***********************HAI****************");
float scale = Math.min(hScale, vScale);
setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec),
resolveSize((int) (mDialHeight * scale), heightMeasureSpec));
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mChanged = true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// // here changes on every tick//////
// / ////
// / //
// //////
// // ///
// //
boolean changed = mChanged;
if (changed) {
mChanged = false;
}
boolean seconds = mSeconds;
if (seconds) {
mSeconds = false;
}
int availableWidth = 100;
int availableHeight = 200;
int x = availableWidth / 2;
int y = availableHeight / 2;
final Drawable dial = mDial;
int w = dial.getIntrinsicWidth();
int h = dial.getIntrinsicHeight();
boolean scaled = false;
if (availableWidth < w || availableHeight < h) {
scaled = true;
float scale = Math.min((float) availableWidth / (float) w,
(float) availableHeight / (float) h);
canvas.save();
canvas.scale(scale, scale, x, y);
}
if (changed) {
dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
dial.draw(canvas);
canvas.save();
canvas.rotate(mHour / 12.0f * 360.0f, x, y);
final Drawable hourHand = mHourHand;
if (changed) {
w = hourHand.getIntrinsicWidth();
h = hourHand.getIntrinsicHeight();
hourHand.setBounds(x - (w / 2), y - (h / 3), x + (w / 2), y + (h / 3));
}
hourHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mMinutes / 60.0f * 360.0f, x, y);
// canvas.rotate(mSecond, x, y);
final Drawable minuteHand = mMinuteHand;
if (changed) {
w = minuteHand.getIntrinsicWidth();
h = minuteHand.getIntrinsicHeight();
minuteHand.setBounds(x - (w / 2), y - (h / 3), x + (w / 2), y + (h / 3));
}
minuteHand.draw(canvas);
canvas.restore();
canvas.save();
canvas.rotate(mSecond, x, y);
// minuteHand = mMinuteHand;
if (seconds) {
w = mSecondHand.getIntrinsicWidth();
h = mSecondHand.getIntrinsicHeight();
mSecondHand.setBounds(x - (w / 2), y - (h / 3), x + (w / 2), y + (h / 3));
}
mSecondHand.draw(canvas);
canvas.restore();
if (scaled) {
canvas.restore();
}
}
MyCount counter = new MyCount(10000, 1000);
public class MyCount extends CountDownTimer {
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
counter.start();
}
#Override
public void onTick(long millisUntilFinished) {
mCalendar.setToNow();
int hour = mCalendar.hour;
int minute = mCalendar.minute;
int second = mCalendar.second;
mSecond = 6.0f * second;
mSeconds = true;
// mChanged = true;
AnalogClock2.this.invalidate();
// Toast.makeText(mContext, "text", Toast.LENGTH_LONG).show();
}
}
boolean mSeconds = false;
float mSecond = 0;
private void onTimeChanged() {
mCalendar.setToNow();
int hour = mCalendar.hour+4;
int minute = mCalendar.minute+15;
int second = mCalendar.second;
mMinutes = minute + second / 60.0f;
mHour = hour + mMinutes / 60.0f;
mChanged = true;
}
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
}
mCalendar = new Time(mtimezone);
onTimeChanged();
invalidate();
}
};
}