Translate

Sunday, May 17, 2020

Code to create round circle , round corner rectangle , round corner rectangles with arrow image in Android


layout.xml :

<LinearLayout
            android:id="@+id/search_editor_tab_max_hoa_fees_row"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/search_editor_tab_row_margin"
            android:background="?android:attr/selectableItemBackground"
            android:orientation="vertical"
            android:visibility="visible">

            <LinearLayout
                android:gravity="center_vertical"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/search_editor_tab_row_margin"
                android:orientation="horizontal">
                <TextView
                    android:id="@+id/max_hoa_fees_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentTop="true"
                    android:text="@string/max_hoa_fees"
                    android:textColor="@color/filter_header"
                    android:textStyle="bold"
                    android:textSize="@dimen/filter_text_size" />
                <com.androidlib.util.InfoButton
                    android:layout_toRightOf="@id/hide_pending_contingent_listings_title"
                    android:padding="@dimen/base_line_grid_size_standard"
                    android:id="@+id/max_hoa_fees_info"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"

                    android:src="@drawable/ic_hoa_info" />
            </LinearLayout>

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="@dimen/search_editor_tab_row_margin"
                android:layout_marginTop="@dimen/search_editor_tab_row_margin"
                android:layout_marginLeft="@dimen/search_editor_tab_row_margin">
                <com.searcheditor.view.FancyWidthExtendableRadioView
                    android:layout_marginRight="@dimen/three_d_tour_shadow_size"
                    android:id="@+id/search_editor_tab_max_hoa_fees_options"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:ballColor="@color/primary"
                    app:selectedTextColor="@color/white"
                    app:circleRadius="@dimen/search_editor_fancy_radio_circle_radius"
                    app:textColor="@color/filter_description"
                    app:textSize="@dimen/default_text_size"
                    android:overScrollMode="always"
                    app:values="@array/fancy_radio_max_hoa_fees_options"
                    android:layout_centerVertical="true"/>
                <ImageView
                    android:layout_marginRight="@dimen/three_d_tour_shadow_size"
                    android:id="@+id/hoa_fee_arrow_icon"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/ic_arrow_down_black"
                    android:layout_centerVertical="true"
                    android:layout_alignRight="@+id/search_editor_tab_max_hoa_fees_options"
                    android:layout_alignEnd="@+id/search_editor_tab_max_hoa_fees_options" />
            </RelativeLayout>


            <RelativeLayout
                android:id="@+id/max_hoa_fees_editor_row"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/search_editor_tab_row_margin"
                android:layout_marginRight="@dimen/search_editor_tab_row_margin"
                android:layout_marginBottom="@dimen/search_editor_tab_row_margin"
                android:background="?android:attr/selectableItemBackground"
                android:visibility="gone">

                <TextView
                    android:id="@+id/editor_max_hoa_fees_dollar_sign"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentLeft="true"
                    android:layout_centerVertical="true"
                    android:text="$"
                    android:textColor="@color/filter_header"
                    android:textSize="@dimen/default_text_size"/>
                <!-- HOA input number should allow max 6 digits with comma separator -->
                <EditText
                    android:id="@+id/enter_max_hoa_fees_editor"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_toRightOf="@+id/editor_max_hoa_fees_dollar_sign"
                    android:hint="@string/max_hoa_fees_label"
                    android:inputType="number"
                    android:maxLength="6"
                    android:paddingLeft="4dp"
                    android:imeOptions="actionDone"
                    android:textColorHint="@color/filter_description"
                    android:textSize="@dimen/default_text_size"/>
            </RelativeLayout>


            <RelativeLayout
                android:id="@+id/search_editor_tab_show_homes_hoa_not_known_row"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="?android:attr/selectableItemBackground"
                android:layout_marginBottom="@dimen/search_editor_tab_row_margin"
                android:visibility="gone">

                <TextView
                    android:id="@+id/show_homes_hoa_not_known_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentLeft="true"
                    android:layout_alignParentTop="true"
                    android:layout_marginLeft="@dimen/search_editor_tab_row_margin"
                    android:text="@string/homes_hoa_not_known"
                    android:textColor="@color/filter_description" />

                <androidx.appcompat.widget.SwitchCompat
                    android:id="@+id/show_homes_hoa_not_known_switch"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentRight="true"
                    android:layout_alignParentTop="true"
                    android:layout_marginRight="@dimen/search_editor_tab_row_margin"
                    android:layout_marginLeft="4dp"
                    android:checked="false"
                    android:theme="@style/SwitchButton" />
            </RelativeLayout>

            <View
                android:id="@+id/search_editor_tab_max_hoa_fees_separator"
                style="@style/separator_line" />
        </LinearLayout>


FancyWidthExtendableRadioView.java:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

/** * This is a fancy radio view wherein we can select individual items */public class FancyWidthExtendableRadioView extends FancyRadioView {
    private int mDrawnTextLeftPosition[] , mDrawnTextRightPosition[];
    private ImageView mArrowImage;
    private int mArrowMargin = 14;
    private final int mMarginDivider = 6;

    public FancyWidthExtendableRadioView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDrawnTextLeftPosition = new int[mValues.length];
        mDrawnTextRightPosition = new int[mValues.length];
    }

    /**     * Handles drawing of the circle / range highlight.     *     * @param canvas Canvas     */    @Override    protected void initSelectionDrawing(Canvas canvas) {

        if (isLargeText()) {
            // For even number of selections / touches (other than 'Any' option),            // the last selection would be set.            // Draw the round cornered rectangle to show the range.            drawRoundCorneredRectangle(canvas);
        } else {
            // Draw circle when there is no range selected            super.drawCircle(canvas);
        }
    }

    @Override    protected void handleTextColor(Canvas canvas, int pos, float textPosition) {
        super.handleTextColor(canvas, pos, textPosition);
    }

    @Override    protected void onDraw(Canvas canvas) {
        // Handle drawing of the selection        initSelectionDrawing(canvas);

        // Draw text and with right color        for (int i = 0; i < mValues.length; i++) {
            drawTextWithColor(canvas, i);
        }
    }

    private void drawTextWithColor(Canvas canvas, int i) {

        // Draw text        String value = mValues[i].toString();

        float textPosition;
        //From Second element we are moving items to left side because Third element has large text and that should fit inside screen.        //so we are making space adjustments here, We are not moving first element to left side because it should be align leftside with its all above circles...        if(i > 0) {

            textPosition = (getButtonCenterX(i)/ mMarginDivider) + mTextWidths[i];
        } else {
            textPosition = getButtonCenterX(i) - mTextWidths[i] / 2;
        }

        mDrawnTextLeftPosition[i] = (int)(textPosition);
        mDrawnTextRightPosition[i] = (int)(textPosition+mTextWidths[i]);
        drawTextInCanvas(canvas, value, textPosition, mTextPaint , i);

        // Handle text color.        handleTextColor(canvas, i, textPosition);
    }

    private void drawTextInCanvas(Canvas canvas, CharSequence mValue, float textPosition, Paint p, int index) {
        canvas.drawText(
                String.valueOf(mValue), textPosition, getHeight() / 2.0f - (p.descent() + p.ascent()) / 2, p);
        //Arrow image need to draw beside MaxHOA label, we have to get the last label right position and place beside accordingly...        if (index == 2) {
            mArrowImage.setX(mDrawnTextRightPosition[2] + mArrowMargin);
        }
    }

    @Override    public boolean onTouch(View v, MotionEvent event) {
        if (mAnimator != null) return true;

        if (event.getAction() == MotionEvent.ACTION_UP) {

            // Find the closest position that has been clicked.            int closest = 0;
            for (int i = 0; i < mDrawnTextLeftPosition.length; i++) {

                if ((mDrawnTextLeftPosition[i] <= event.getX()) && (event.getX() <= mDrawnTextRightPosition[i])) {

                    closest = i;

                    // Handle animation of the selection and set the last selection                    handleAnimationAndUpdateSelection(closest);

                    // Update values                    invokeValueChangedListener();
                    invalidate();
                    break;
                }
            }
        }
        return true;
    }

    /**     * @param newSelection closest index value that user intended to touch     */    @Override    protected void handleAnimationAndUpdateSelection(int newSelection) {

        if (mRuntimeDrawValues == null) return;

        // Increment the tap count.        mRuntimeDrawValues.tapCount++;

        animateSelectionChange(newSelection, newSelection);
        mRuntimeDrawValues.tapCount = 0;
        setDrawValues(newSelection, newSelection);
    }


    private void setDrawValues(int last, int current) {
        mRuntimeDrawValues.lastSelection = last;
        mRuntimeDrawValues.selection = current;
    }

    /**     * Updates the values when new radio button values are selected     */    @Override    protected void invokeValueChangedListener() {
        if (mOnValueChangedListener != null) {

            // Updates the values based on if its a range selection or not.            if (isLargeText()) {

                mOnValueChangedListener.valueUpdated(this,
                        // Since user can select a 'lastSelection' such that either its less than or                        // more than the currently selected value. That's why Math.min().                        mRuntimeDrawValues.selection,
                        mRuntimeDrawValues.selection,
                        String.valueOf(mValues[mRuntimeDrawValues.selection]));
            } else {
                super.invokeValueChangedListener();
            }
        }
    }

    /**     * This method draws a round cornered rectangle selection like:     *  _______     * (_______)     * <p>
     * This is to display when a range is selected for the radio buttons.     *     * @param canvas Canvas     */    private void drawRoundCorneredRectangle(Canvas canvas) {
        // Create a rectangle with the 4 corner .        // Set an offset value in pixels to draw rounded rectangle on canvas        float left=0 , right=0;
        int margin = 25;

        //Third element has big length text, We need to handle that..        if(mRuntimeDrawValues.selection > 0) {
            left = ((getButtonCenterX(mRuntimeDrawValues.selection)/ mMarginDivider) + mTextWidths[mRuntimeDrawValues.selection]) - margin ;

            //Here last HOAFee label in canvas has arrow icon on its right and the circle need to cover that ..So right side we need to have more margin for circle            if(mRuntimeDrawValues.selection == 2)
                right = left + mTextWidths[mRuntimeDrawValues.selection] + (3 * margin + mArrowMargin) ;
            else                right = left + mTextWidths[mRuntimeDrawValues.selection] + (2 * margin) ;
        }

        float top = ((getHeight() / 2f) + getCircleRadius()) - 4 ;
        float bottom =  (-1 * (getHeight() / 2f) + getCircleRadius()) + 4 ;

        RectF rect = new RectF(
                left, // left                top, // top                right, // right                bottom // bottom        );

        // Finally, draw the rounded corners rectangle object on the canvas        canvas.drawRoundRect(
                rect, // rect                getCircleRadius(), // rx                getCircleRadius(), // ry                mBallPaint // Paint        );
    }

    /**     * Checks whether the current selection is a range or just single value.     * See onTouch in super class, to see when lastSelection is set.     *     * @return bool     */    protected boolean isLargeText() {
        return mRuntimeDrawValues != null                // If there is only one selection and last selection is -1 (default), then no range.                && mRuntimeDrawValues.lastSelection != NO_SELECTION                // If last selection is for some reason same as current, then its not a range                && mRuntimeDrawValues.selection != 0;
    }

    /**     * Sets the current selections Text in a specified index     */    public void setSelectionText(String strSelection) {
        // Need to update the Third label in the canvas        mValues[2] = strSelection ;
        // Refresh the canvas with updated text        this.invalidate();
    }

    public void drawSelectionInCanvas(int selectionItem){

        // Handle animation of the selection and set the last selection        handleAnimationAndUpdateSelection(selectionItem);
        // Refresh the canvas with updated text        this.invalidate();
    }

    public void setImage(ImageView mArrowImage) {
        this.mArrowImage = mArrowImage;
    }

}




FancyRadioView.java :
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;

public class FancyRadioView extends View implements View.OnTouchListener {
    static final int NO_SELECTION = -1;
    //Paints and Colors    Paint mTextPaint;
    Paint mTextLargePaint;
    Paint mTextSmallPaint;
    Paint mSelectedTextPaint;
    Paint mSelectedTextLargePaint;
    Paint mSelectedTextSmallPaint;
    Paint mBallPaint;

    int mTextColor = Color.BLACK;
    int mSelectedColor = Color.WHITE;
    int mBallColor = Color.RED;

    CharSequence[] mValues;         //The options, provided by custom:mValues    float[] mTextWidths;            //Measurements for the text
    float mDensityMultiplier;       //Pixel to DP Scale    float mScaledDensityMultiplier;
    float mTextSizeDP = 12;
    float mTextLargeSizeDP = 14;
    float mTextSmallSizeDP = 11;
    float mPaddingDP = 48;
    float mCircleRadiusDP = 23;
    float mStrokeWidth = 1f;
    boolean mStroked = false;

    ValueAnimator mAnimator;        //Null when no animation, and the animation when there is
    RuntimeDrawValues mRuntimeDrawValues = new RuntimeDrawValues();
    OnValueChangedListener mOnValueChangedListener;

    //We serialize this up to know the current state of the view    public static class RuntimeDrawValues implements Serializable {
        // Denotes current selection / touch.        int selection;
        // Denotes previous selection.        // In case of range selection, this is set to the last value that was selected in the range .        int lastSelection = NO_SELECTION;
        int tapCount;
    }

    public FancyRadioView(Context context, AttributeSet attrs) {
        super(context, attrs);
        calculateDensity();
        initAttributes(attrs);
        initPaint();
        measureOptions();
        setOnTouchListener(this);
    }

    // Use a stroked rather than a filled circle or range.    public void setStroked(boolean isStroked) {
        mStroked = isStroked;
        if (mBallPaint != null) {
            mBallPaint.setStyle(Paint.Style.STROKE);
            mBallPaint.setStrokeWidth(getStrokeWidth());
        }

        // If the ball is stroked, make the selected color to be the same as the stroke color.        // If the A/B test declares the stroke mode to be a winner, set this        // value in the XML app:selectedTextColor        if (isStroked) {
            mSelectedColor = mBallColor;
            mSelectedTextPaint.setColor(mSelectedColor);
            mSelectedTextLargePaint.setColor(mSelectedColor);
            mSelectedTextSmallPaint.setColor(mSelectedColor);
        }
    }

    float getStrokeWidth() {
        return mStrokeWidth * mDensityMultiplier;
    }

    private void calculateDensity() {
        DisplayMetrics dm = new DisplayMetrics();
        if (isInEditMode()) {
            //This uses reflection to get the display metrics from the BridgeContext which isn't            //available to our code            Context ctx = getContext();
            Class c = ctx.getClass();
            try {
                dm = (DisplayMetrics) c.getMethod("getMetrics").invoke(ctx);
                mDensityMultiplier = dm.density;
                mScaledDensityMultiplier = dm.scaledDensity;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        } else {
            dm = Resources.getSystem().getDisplayMetrics();
            mDensityMultiplier = dm.density;
            mScaledDensityMultiplier = dm.scaledDensity;
        }
    }

    //Requires density lookup    private void initPaint() {
        mTextPaint = new Paint();
        mTextPaint.setTextSize(mDensityMultiplier * mTextSizeDP);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setAntiAlias(true);

        mTextLargePaint = new Paint();
        mTextLargePaint.setTextSize(mDensityMultiplier * mTextLargeSizeDP);
        mTextLargePaint.setColor(mTextColor);
        mTextLargePaint.setAntiAlias(true);

        mTextSmallPaint = new Paint();
        mTextSmallPaint.setTextSize(mDensityMultiplier * mTextSmallSizeDP);
        mTextSmallPaint.setColor(mTextColor);
        mTextSmallPaint.setAntiAlias(true);

        mSelectedTextPaint = new Paint();
        mSelectedTextPaint.setTextSize(mDensityMultiplier * mTextSizeDP);
        mSelectedTextPaint.setColor(mSelectedColor);
        mSelectedTextPaint.setAntiAlias(true);

        mSelectedTextLargePaint = new Paint();
        mSelectedTextLargePaint.setTextSize(mDensityMultiplier * mTextLargeSizeDP);
        mSelectedTextLargePaint.setColor(mSelectedColor);
        mSelectedTextLargePaint.setAntiAlias(true);

        mSelectedTextSmallPaint = new Paint();
        mSelectedTextSmallPaint.setTextSize(mDensityMultiplier * mTextSmallSizeDP);
        mSelectedTextSmallPaint.setColor(mSelectedColor);
        mSelectedTextSmallPaint.setAntiAlias(true);

        mBallPaint = new Paint();
        mBallPaint.setColor(mBallColor);
        mBallPaint.setAntiAlias(true);
    }

    // Measure the PX width of the options    // Requires paint to be init'd already    private void measureOptions() {
        mTextWidths = new float[mValues.length];
        for (int i = 0; i < mValues.length; i++) {
            mTextWidths[i] = mTextPaint.measureText(mValues[i], 0, mValues[i].length());
        }
    }

    //Apply the custom attributes to the view.    // Requires density to be looked up already    private void initAttributes(AttributeSet attrs) {
        TypedArray a = getContext().getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.fancy_radio_view_attribs,
                0, 0);

        //Mandatory values array (Buggy in editor, only returns the first element?)        mValues = a.getTextArray(R.styleable.fancy_radio_view_attribs_values);
        Preconditions.checkNotNull(mValues,
                "Need to provide mValues attribute point to a" +
                        "string array resource on your fancy radio view");

        //Size Attributes        mCircleRadiusDP = a.getDimensionPixelSize(R.styleable.fancy_radio_view_attribs_circleRadius,
                (int) (mCircleRadiusDP * mDensityMultiplier)) / mDensityMultiplier;
        mPaddingDP = a.getDimensionPixelSize(R.styleable.fancy_radio_view_attribs_padding,
                (int) (mPaddingDP * mDensityMultiplier)) / mDensityMultiplier;
        mTextSizeDP = a.getDimensionPixelSize(R.styleable.fancy_radio_view_attribs_textSize,
                (int) (mTextSizeDP * mDensityMultiplier)) / mDensityMultiplier;

        //Color Attribs        mBallColor = a.getColor(R.styleable.fancy_radio_view_attribs_ballColor, mBallColor);
        mTextColor = a.getColor(R.styleable.fancy_radio_view_attribs_textColor, mTextColor);
        mSelectedColor = a.getColor(R.styleable.fancy_radio_view_attribs_selectedTextColor, mSelectedColor);

        a.recycle();
    }

    public void setOnValueChangedListener(OnValueChangedListener mOnValueChangedListener) {
        this.mOnValueChangedListener = mOnValueChangedListener;
    }

    /**     * Sets the current selections index value     * * @param selection Current Selection     */    public void setSelection(int selection) {
        mRuntimeDrawValues.selection = selection;
        mRuntimeDrawValues.lastSelection = NO_SELECTION;
        if (selection == 0) mRuntimeDrawValues.tapCount = 0;
        postInvalidate();
    }

    /**     * Sets the current selections index value, and makes a valueUpdated callback. Useful for autotest     *     * @param selection Current Selection     */    public void setSelectionWithCallback(int selection) {
        setSelection(selection);
        invokeValueChangedListener();
    }

    /**     * Gets the current selections index value     *     * @return the currently selected index     */    public int getSelection() {
        return mRuntimeDrawValues.selection;
    }

    /**     * Gets the current selections Text as a String     *     * @return the currently selected text     */    public String getSelectionText() {
        return String.valueOf(mValues[mRuntimeDrawValues.selection]);
    }


    @Override    protected void onDraw(Canvas canvas) {
        // Handle drawing of the selection        initSelectionDrawing(canvas);

        // Draw text and with right color        for (int i = 0; i < mValues.length; i++) {
            drawOptionText(canvas, i);
        }
    }

    /**     * Handles drawing of the circle / range highlight.     *     * @param canvas Canvas     */    protected void initSelectionDrawing(Canvas canvas) {
        drawCircle(canvas);
    }

    protected void drawCircle(Canvas canvas) {
        if (mAnimator == null) {
            drawCircle(canvas, getButtonCenterX(mRuntimeDrawValues.selection));
        } else {
            Float val = (Float) mAnimator.getAnimatedValue();
            drawCircle(canvas, val);
        }
    }

    private void drawOptionText(Canvas canvas, int i) {

        // Draw text        String value = mValues[i].toString();
        if (value.contains("\n")) {
            String[] texts = value.split("\n");
            for (int m = 0; m < texts.length; m++) {

                Paint paint = m == 0 ? mTextLargePaint : mTextSmallPaint;
                Paint selectedPaint = m == 0 ? mSelectedTextLargePaint : mSelectedTextSmallPaint;

                //We calculate the center and then offset by half the width to the left (center on button)                float textPosition = getButtonCenterX(i) - paint.measureText(texts[m], 0, texts[m].length()) / 2;

                //padding top and bottom                float unpaddedHeight = (float) (getHeight() * 0.70);
                float textPositionY = (getHeight() - unpaddedHeight) / 2 + unpaddedHeight * (m + 1) / (texts.length + 1);

                drawText(canvas, texts[m], textPosition, textPositionY, paint);

                // Handle text color.                handleTextColor(canvas, i, texts[m], textPosition, textPositionY, selectedPaint);
            }
        } else {

            //We calculate the center and then offset by half the width to the left (center on button)            float textPosition = getButtonCenterX(i) - mTextWidths[i] / 2;

            drawText(canvas, value, textPosition, mTextPaint);

            // Handle text color.            handleTextColor(canvas, i, textPosition);
        }
    }

    /**     * Handle text color for the current position in question for which text is  being drawn.     *     * @param canvas       canvas     * @param i            index of the value in the array which needs to be drawn     * @param textPosition exact position where the text needs to be draw     */    protected void handleTextColor(Canvas canvas, int i, float textPosition) {
        handleTextColor(canvas, i, mValues[i], textPosition, getHeight() / 2.0f, mSelectedTextPaint);
    }

    protected void handleTextColor(Canvas canvas, int i, CharSequence text, float textPosition, float textPositionY, Paint selectedPaint) {

        // If current selection, then make it light.        if (mRuntimeDrawValues.selection == i) {
            handleTextFadeIn(canvas, text, textPosition, textPositionY, selectedPaint);
        } else if (mRuntimeDrawValues.lastSelection == i) {
            handleTextFadeOut(canvas, text, textPosition, textPositionY, selectedPaint);
        }
    }

    private void drawText(Canvas canvas, CharSequence mValue, float textPosition, Paint p) {
        canvas.drawText(
                String.valueOf(mValue), textPosition, getHeight() / 2.0f - (p.descent() + p.ascent()) / 2, p);
    }

    private void drawText(Canvas canvas, CharSequence mValue, float textPosition, float textPositionY, Paint p) {
        canvas.drawText(
                String.valueOf(mValue), textPosition, textPositionY - (p.descent() + p.ascent()) / 2, p);
    }

    private void handleTextFadeOut(Canvas canvas, CharSequence text, float textPosition, float textPositionY, Paint selectedPaint) {
        if (mAnimator != null) {
            float f = mAnimator.getAnimatedFraction();
            selectedPaint.setAlpha((int) ((1f - f) * 255));
            drawText(canvas, text, textPosition, textPositionY, selectedPaint);
        }
    }

    /**     * Draws the text fading to white     *     * @param canvas       canvas     * @param i            index of the value in the array which needs to be drawn     * @param textPosition exact position where the text needs to be draw     */    protected void handleTextFadeIn(Canvas canvas, int i, float textPosition) {
        handleTextFadeIn(canvas, mValues[i], textPosition, getHeight() / 2.0f, mSelectedTextPaint);
    }

    protected void handleTextFadeIn(Canvas canvas, CharSequence text, float textPosition, float textPositionY, Paint selectedPaint) {
        //If we are drawing the selection field we want to fade with the animation        float f = mAnimator != null ? mAnimator.getAnimatedFraction() : 1;
        selectedPaint.setAlpha((int) (f * 255));
        drawText(canvas, text, textPosition, textPositionY, selectedPaint);
    }

    /**     * We measure this view, this is called by the system.     * <p>
     * we call setMeasuredDimensions at the end that fits the component as appropriate, inflates     * to the view, or uses specific sizes     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int desiredWidth = (int) (getButtonCenterX(mValues.length - 1) + getCircleRadius());
        int desiredHeight = (int) (getCircleRadius() * 2);

        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.max(desiredWidth, widthSize);
        } else {
            width = desiredWidth;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            height = Math.max(desiredHeight, heightSize);
        } else {
            height = desiredHeight;
        }

        //MUST CALL THIS        setMeasuredDimension(width, height);
    }

    private void drawCircle(Canvas canvas, float center_pos) {
        if (mStroked) {
            canvas.drawCircle(center_pos, getHeight() / 2f,
                    getCircleRadius() - getStrokeWidth(), mBallPaint);
        } else {
            canvas.drawCircle(center_pos, getHeight() / 2f,
                    getCircleRadius(), mBallPaint);
        }
    }

    protected float getCircleRadius() {
        return mCircleRadiusDP * mScaledDensityMultiplier;
    }

    protected float getButtonCenterX(int selection) {
        /*         * We want the left edge of the leftmost circle to touch the end edge of the view,         * and the same for the right side         */        float circleRadius = getCircleRadius();
        int separationWidth = (int) ((getWidth() - (circleRadius * 2)) /
                ((float) (mValues.length - 1)));
        return separationWidth * selection + circleRadius;
    }

    @Override    public boolean onTouch(View v, MotionEvent event) {
        if (mAnimator != null) return true;

        if (event.getAction() == MotionEvent.ACTION_UP) {
            // Find the closest position that has been clicked.            int closest = 0;
            int min_dist = 1000000;
            for (int i = 0; i < mValues.length; i++) {
                int distance = (int) Math.abs(getButtonCenterX(i) - event.getX());
                if (distance < min_dist) {
                    min_dist = distance;
                    closest = i;
                }
            }

            // Handle animation of the selection and set the last selection            handleAnimationAndUpdateSelection(closest);

            // Update values            invokeValueChangedListener();

            invalidate();
        }
        return true;
    }

    /**     * Handles animating the new change based on touch.     *     * @param closest closes index value that user intended to touch     */    protected void handleAnimationAndUpdateSelection(int closest) {
        animateSelectionChange(mRuntimeDrawValues.selection, closest);
        // Set the last selection to the current one        mRuntimeDrawValues.lastSelection = mRuntimeDrawValues.selection;
        // Set current selection        mRuntimeDrawValues.selection = closest;
    }

    /**     * Perform animation     *     * @param old          from position     * @param newSelection to position     */    protected void animateSelectionChange(final int old, final int newSelection) {
        mAnimator = new ValueAnimator();
        mAnimator.setDuration(300);
        mAnimator.setFloatValues(getButtonCenterX(old), getButtonCenterX(newSelection));

        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override            public void onAnimationUpdate(ValueAnimator animation) {
                invalidate();
            }
        });
        mAnimator.addListener(new Animator.AnimatorListener() {
            @Override            public void onAnimationStart(Animator animation) {

            }

            @Override            public void onAnimationEnd(Animator animation) {
                mAnimator = null;
            }

            @Override            public void onAnimationCancel(Animator animation) {

            }

            @Override            public void onAnimationRepeat(Animator animation) {

            }
        });
        mAnimator.start();
    }

    /**     * Send value selected updates to model /server.     */    protected void invokeValueChangedListener() {
        if (mOnValueChangedListener != null) {
            mOnValueChangedListener.valueUpdated(this,
                    mRuntimeDrawValues.selection,
                    null,
                    String.valueOf(mValues[mRuntimeDrawValues.selection]));
        }
    }

    public interface OnValueChangedListener {
        void valueUpdated(FancyRadioView radioView, int startRange, Integer endRange, String selectionText);
    }

    @Override    protected Parcelable onSaveInstanceState() {
        Bundle b = new Bundle();
        b.putParcelable("parent", super.onSaveInstanceState());
        b.putSerializable("state", mRuntimeDrawValues);
        return b;
    }

    @Override    protected void onRestoreInstanceState(Parcelable state) {
        Bundle b = (Bundle) state;
        mRuntimeDrawValues = (RuntimeDrawValues) b.getSerializable("state");
        super.onRestoreInstanceState(b.getParcelable("parent"));
        invalidate();
    }
}









MainActivity.java :
private FancyWidthExtendableRadioView mMaxHoaFees;
private static String HOA_MODE_MAX = "HOA_MODE_MAX";
private EditText mMaxHoaFeesEditor;
mMaxHoaFees = viewGroup.findViewById(R.id.search_editor_tab_max_hoa_fees_options);

FancyRadioView.OnValueChangedListener mValueChangedListener = new FancyValueChangedListener();
mMaxHoaFees.setOnValueChangedListener(mValueChangedListener);


private class FancyValueChangedListener implements FancyRadioView.OnValueChangedListener {
    @Override    public void valueUpdated(FancyRadioView radioView, int startRange, Integer endRange, String selectionText) {
        //AB test for reorder filter action        HashMap<String, String> params = new HashMap<>();

        if (radioView == mMaxHoaFees) {

            if (startRange == 0) {
                //HOA option "Any"                resetHOAToAny(false);
            } else if (startRange == 1) {
                //HOA option "No HOA"                hideSoftKeyboard();
                mMaxHoaFeesEditorRow.setVisibility(View.GONE);
                mHoaFeeArrowIcon.setBackgroundResource(R.drawable.ic_arrow_down_black);

                Settings.setHoaFilterMode(getContext() , HOA_MODE_NONE);
                resetHoaFees();
                mSearchEditorSelections.noHoaFee = true;
                mShowHomesHoaNotKnownRow.setVisibility(View.GONE);

                if (mMaxHoaFeesEditor.getText().toString().length() > 0) {
                    // Condition to display price on top of HOAFee label when user entered price and click on Any/NOHoa label                    mMaxHoaFeesOnOffFlag = true;
                    mMaxHoaFees.setSelectionText("Max $" + mMaxHoaFeesEditor.getText().toString() + "/month");
                }

            } else if (startRange == 2) {
                //HOA option "Enter Max Hoa fees                if (showHomeWithoutHoaInfoCheckBox.isChecked()) {
                    mSearchEditorSelections.hoaFeeOptional = hoaMaxFee;
                    mSearchEditorSelections.hoaMaxFee = null;
                } else {
                    mSearchEditorSelections.hoaFeeOptional = null;
                    mSearchEditorSelections.hoaMaxFee = hoaMaxFee;
                }

                Settings.setHoaFilterMode(getContext() , HOA_MODE_MAX);
                mSearchEditorSelections.noHoaFee = null;
                mMaxHoaFeesEditorRow.setVisibility(View.VISIBLE);
                mShowHomesHoaNotKnownRow.setVisibility(View.VISIBLE);
                mMaxHoaFeesEditor.requestFocus();
                InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
                //while user click on MaxHoa button then we need to update arrow up/down..                mHoaFeeArrowIcon.setBackgroundResource(R.drawable.ic_arrow_up_red);
                maxHoaFeesInputHandle();
            }
           
        }
    }
}



Output :



No comments:

Post a Comment

Could not identify launch activity: Default activity not found : Error while Launching activity

Problem : I got this Error , When I tried to create an application without any Activity . Basically like to develop an Android Headless appl...