Java tutorial
package br.com.mauker.materialseekbar; /* * Copyright 2014, Appyvet, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.LightingColorFilter; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v4.content.ContextCompat; import android.util.Log; import android.util.TypedValue; import android.view.View; /** * Represents a thumb in the RangeBar slider. This is the handle for the slider * that is pressed and slid. */ public class PinView extends View { private static final String LOG_TAG = PinView.class.getSimpleName(); // Private Constants /////////////////////////////////////////////////////// // The radius (in dp) of the touchable area around the thumb. We are basing // this value off of the recommended 48dp Rhythm. See: // http://developer.android.com/design/style/metrics-grids.html#48dp-rhythm private static final float MINIMUM_TARGET_RADIUS_DP = 24; // Sets the default values for radius, normal, pressed if circle is to be // drawn but no value is given. private static final float DEFAULT_THUMB_RADIUS_DP = 14; // Member Variables //////////////////////////////////////////////////////// // Radius (in pixels) of the touch area of the thumb. private float mTargetRadiusPx; // Indicates whether this thumb is currently pressed and active. private boolean mIsPressed = false; // The y-position of the thumb in the parent view. This should not change. private float mY; // The current x-position of the thumb in the parent view. private float mX; // mPaint to draw the thumbs if attributes are selected private Paint mTextPaint; private Drawable mPin; // The displayed value on the pin, when selected. private String mValue; // Radius of the new thumb if selected private int mPinRadiusPx; private ColorFilter mPinFilter; private float mPinPadding; private float mTextYPadding; private Rect mBounds = new Rect(); private float mDensity; private Paint mCirclePaint; private float mCircleRadiusPx; private float mMinPinFont = BuildConfig.DEFAULT_PIN_MIN_FONT; private float mMaxPinFont = BuildConfig.DEFAULT_PIN_MAX_FONT; private boolean mIsTemporary; private boolean mHasBeenPressed = false; // ---------- Constructors ---------- // public PinView(Context context) { super(context); } // ---------- Initialization ---------- // /** * The view is created empty with a default constructor. Use init to set all the initial * variables for the pin * * @param ctx Context * @param y The y coordinate to raw the pin (i.e. the bar location) * @param pinRadiusDP the initial size of the pin * @param pinColor the color of the pin * @param textColor the color of the value text in the pin * @param circleRadius the radius of the selector circle * @param minFont the minimum font size for the pin text * @param maxFont the maximum font size for the pin text * @param pinsAreTemporary whether to show the pin initially or just the circle */ public void init(Context ctx, float y, float pinRadiusDP, int pinColor, int textColor, float circleRadius, int circleColor, float minFont, float maxFont, boolean pinsAreTemporary) { Resources res = ctx.getResources(); mPin = ContextCompat.getDrawable(ctx, R.drawable.rotate); mDensity = getResources().getDisplayMetrics().density; mMinPinFont = minFont / mDensity; mMaxPinFont = maxFont / mDensity; mIsTemporary = pinsAreTemporary; mPinPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, res.getDisplayMetrics()); mCircleRadiusPx = circleRadius; mTextYPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8f, res.getDisplayMetrics()); // If one of the attributes are set, but the others aren't, set the // attributes to default if (pinRadiusDP == -1) { mPinRadiusPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_THUMB_RADIUS_DP, res.getDisplayMetrics()); } else { mPinRadiusPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, pinRadiusDP, res.getDisplayMetrics()); } //Set text size in px from dp int textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 5, res.getDisplayMetrics()); // Creates the paint and sets the Paint values mTextPaint = new Paint(); mTextPaint.setColor(textColor); mTextPaint.setAntiAlias(true); mTextPaint.setTextSize(textSize); // Creates the paint and sets the Paint values mCirclePaint = new Paint(); mCirclePaint.setColor(circleColor); mCirclePaint.setAntiAlias(true); //Color filter for the selection pin mPinFilter = new LightingColorFilter(pinColor, pinColor); // Sets the minimum touchable area, but allows it to expand based on // image size int targetRadius = (int) Math.max(MINIMUM_TARGET_RADIUS_DP, mPinRadiusPx); mTargetRadiusPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, targetRadius, res.getDisplayMetrics()); mY = y; } /** * Set the x value of the pin * * @param x set x value of the pin */ @Override public void setX(float x) { mX = x; } /** * Get the x value of the pin * * @return x float value of the pin */ @Override public float getX() { return mX; } /** * Set the value of the pin * * @param x String value of the pin */ public void setXValue(String x) { mValue = x; } /** * Determine if the pin is pressed * * @return true if is in pressed state * false otherwise */ @Override public boolean isPressed() { return mIsPressed; } /** * Sets the state of the pin to pressed */ public void press() { mIsPressed = true; mHasBeenPressed = true; } /** * Set size of the pin and padding for use when animating pin enlargement on press * * @param size the size of the pin radius * @param padding the size of the padding */ public void setSize(float size, float padding) { mPinPadding = (int) padding; mPinRadiusPx = (int) size; invalidate(); } public void setColor(int circleColor) { mCirclePaint.setColor(circleColor); mPinFilter = new LightingColorFilter(circleColor, circleColor); } /** * Release the pin, sets pressed state to false */ public void release() { mIsPressed = false; } /** * Determines if the input coordinate is close enough to this thumb to * consider it a press. * * @param x the x-coordinate of the user touch * @param y the y-coordinate of the user touch * @return true if the coordinates are within this thumb's target area; * false otherwise */ public boolean isInTargetZone(float x, float y) { return (Math.abs(x - mX) <= mTargetRadiusPx && Math.abs(y - mY + mPinPadding) <= mTargetRadiusPx); } //Draw the circle regardless of pressed state. If pin size is >0 then also draw the pin and text @Override public void draw(Canvas canvas) { //Draw pin if pressed if (mPinRadiusPx > 0 && (mHasBeenPressed || !mIsTemporary)) { // mBounds.set( // (int) mX - mPinRadiusPx, // (int) mY - (mPinRadiusPx * 2) - (int) mPinPadding, // (int) mX + mPinRadiusPx, // (int) mY - (int) mPinPadding // ); mBounds.set((int) mX - mPinRadiusPx, (int) mY - (mPinRadiusPx * 2) - (int) mPinPadding, (int) mX + mPinRadiusPx, (int) mY - (int) mPinPadding); mPin.setBounds(mBounds); String text = mValue; calibrateTextSize(mTextPaint, text, mBounds.width()); mTextPaint.getTextBounds(text, 0, text.length(), mBounds); mTextPaint.setTextAlign(Paint.Align.CENTER); mPin.setColorFilter(mPinFilter); mPin.draw(canvas); canvas.drawText(text, mX, mY - mPinRadiusPx - mPinPadding + mTextYPadding, mTextPaint); } else { canvas.drawCircle(mX, mY, mCircleRadiusPx, mCirclePaint); } super.draw(canvas); } // ----- Private Methods ----- // //Set text size based on available pin width. private void calibrateTextSize(Paint paint, String text, float boxWidth) { paint.setTextSize(mMinPinFont); float textSize = paint.measureText(text); Log.d("pin", "textSize: " + textSize); float estimatedFontSize = boxWidth * 8 / textSize / mDensity; if (estimatedFontSize < mMinPinFont) { estimatedFontSize = mMinPinFont; Log.d("pin", "< mMinPinFont - Value: " + estimatedFontSize); } else if (estimatedFontSize > mMaxPinFont) { estimatedFontSize = mMaxPinFont; Log.d("pin", "> mMaxPinFont - Value: " + estimatedFontSize); } // Log.d("pin","estimatedSize: " + estimatedFontSize); // Log.d("pin","size: " + estimatedFontSize * mDensity); paint.setTextSize(estimatedFontSize * mDensity * 1.5f); } }