Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ArcMenu mainImage I need at the bottom of the screen. OnMeasure is not letting it come at the bottom of the screen

Tags:

java

android

I am trying to bring the mainImg to the bottom of the screen .

 /*
 * Copyright (C) 2012 Capricorn
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License 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.
 */

In ArcLayout OnMeasure if I change size to 0 it's coming down but the animation disappears. How to change the OnMeasure to make the img come down to the bottom of the screen and the height should be taken upwards? Please help!

package com.example.splashscreen;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.Animation.AnimationListener;

/**
 * A Layout that arranges its children around its center. The arc can be set by
 * calling {@link #setArc(float, float) setArc()}. You can override the method
 * {@link #onMeasure(int, int) onMeasure()}, otherwise it is always
 * WRAP_CONTENT.
 * 
 * @author Capricorn
 * 
 */
public class ArcLayout extends ViewGroup {
    /**
     * children will be set the same size.
     */
    private int mChildSize;

    private int mChildPadding = 5;

    private int mLayoutPadding = 10;

    public static final float DEFAULT_FROM_DEGREES = 270.0f;

    public static final float DEFAULT_TO_DEGREES = 360.0f;

    private float mFromDegrees = DEFAULT_FROM_DEGREES;

    private float mToDegrees = DEFAULT_TO_DEGREES;

    private static final int MIN_RADIUS = 150;

    /* the distance between the layout's center and any child's center */
    private int mRadius;

    private boolean mExpanded = false;

    public ArcLayout(Context context) {
        super(context);
    }

    public ArcLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ArcLayout, 0, 0);
            mFromDegrees = a.getFloat(R.styleable.ArcLayout_fromDegrees, DEFAULT_FROM_DEGREES);
            mToDegrees = a.getFloat(R.styleable.ArcLayout_toDegrees, DEFAULT_TO_DEGREES);
            mChildSize = Math.max(a.getDimensionPixelSize(R.styleable.ArcLayout_childSize, 0), 0);

            a.recycle();
        }
    }

    private static int computeRadius(final float arcDegrees, final int childCount, final int childSize,
            final int childPadding, final int minRadius) {
        if (childCount < 2) {
            return minRadius;
        }

        final float perDegrees = arcDegrees / (childCount - 1);
        final float perHalfDegrees = perDegrees / 2;
        final int perSize = childSize + childPadding;

        final int radius = (int) ((perSize / 2) / Math.sin(Math.toRadians(perHalfDegrees)));

        return Math.max(radius, minRadius);
    }

    private static Rect computeChildFrame(final int centerX, final int centerY, final int radius, final float degrees,
            final int size) {

        final double childCenterX = centerX + radius * Math.cos(Math.toRadians(degrees));
        final double childCenterY = centerY + radius * Math.sin(Math.toRadians(degrees));

        return new Rect((int) (childCenterX - size / 2), (int) (childCenterY),
                (int) (childCenterX + size / 2), (int) (childCenterY + size ));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int radius = mRadius = computeRadius(Math.abs(mToDegrees - mFromDegrees), getChildCount(), mChildSize,
                mChildPadding, MIN_RADIUS);
        final int size = radius * 2 + mChildSize + mChildPadding + mLayoutPadding * 2;

        setMeasuredDimension(size, size);

        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).measure(MeasureSpec.makeMeasureSpec(mChildSize, MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(mChildSize, MeasureSpec.EXACTLY));
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int centerX = getWidth() / 2;
        final int centerY = getHeight() / 2;
        final int radius = mExpanded ? mRadius : 0;

        final int childCount = getChildCount();
        final float perDegrees = (mToDegrees - mFromDegrees) / (childCount - 1);

        float degrees = mFromDegrees;
        for (int i = 0; i < childCount; i++) {
            Rect frame = computeChildFrame(centerX, centerY, radius, degrees, mChildSize);
            degrees += perDegrees;
            getChildAt(i).layout(frame.left, frame.top, frame.right, frame.bottom);
        }
    }

    /**
     * refers to {@link LayoutAnimationController#getDelayForView(View view)}
     */
    private static long computeStartOffset(final int childCount, final boolean expanded, final int index,
            final float delayPercent, final long duration, Interpolator interpolator) {
        final float delay = delayPercent * duration;
        final long viewDelay = (long) (getTransformedIndex(expanded, childCount, index) * delay);
        final float totalDelay = delay * childCount;

        float normalizedDelay = viewDelay / totalDelay;
        normalizedDelay = interpolator.getInterpolation(normalizedDelay);

        return (long) (normalizedDelay * totalDelay);
    }

    private static int getTransformedIndex(final boolean expanded, final int count, final int index) {
        if (expanded) {
            return count - 1 - index;
        }

        return index;
    }

    private static Animation createExpandAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta,
            long startOffset, long duration, Interpolator interpolator) {
        Animation animation = new RotateAndTranslateAnimation(0, toXDelta, 0, toYDelta, 0, 720);
        animation.setStartOffset(startOffset);
        animation.setDuration(duration);
        animation.setInterpolator(interpolator);
        animation.setFillAfter(true);

        return animation;
    }

    private static Animation createShrinkAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta,
            long startOffset, long duration, Interpolator interpolator) {
        AnimationSet animationSet = new AnimationSet(false);
        animationSet.setFillAfter(true);

        final long preDuration = duration / 2;
        Animation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f);
        rotateAnimation.setStartOffset(startOffset);
        rotateAnimation.setDuration(preDuration);
        rotateAnimation.setInterpolator(new LinearInterpolator());
        rotateAnimation.setFillAfter(true);

        animationSet.addAnimation(rotateAnimation);

        Animation translateAnimation = new RotateAndTranslateAnimation(0, toXDelta, 0, toYDelta, 360, 720);
        translateAnimation.setStartOffset(startOffset + preDuration);
        translateAnimation.setDuration(duration - preDuration);
        translateAnimation.setInterpolator(interpolator);
        translateAnimation.setFillAfter(true);

        animationSet.addAnimation(translateAnimation);

        return animationSet;
    }

    private void bindChildAnimation(final View child, final int index, final long duration) {
        final boolean expanded = mExpanded;
        final int centerX = getWidth() / 2;
        final int centerY = getHeight() / 2;
        final int radius = expanded ? 0 : mRadius;

        final int childCount = getChildCount();
        final float perDegrees = (mToDegrees - mFromDegrees) / (childCount - 1);
        Rect frame = computeChildFrame(centerX, centerY, radius, mFromDegrees + index * perDegrees, mChildSize);

        final int toXDelta = frame.left - child.getLeft();
        final int toYDelta = frame.top - child.getTop();

        Interpolator interpolator = mExpanded ? new AccelerateInterpolator() : new OvershootInterpolator(1.5f);
        final long startOffset = computeStartOffset(childCount, mExpanded, index, 0.1f, duration, interpolator);

        Animation animation = mExpanded ? createShrinkAnimation(0, toXDelta, 0, toYDelta, startOffset, duration,
                interpolator) : createExpandAnimation(0, toXDelta, 0, toYDelta, startOffset, duration, interpolator);

        final boolean isLast = getTransformedIndex(expanded, childCount, index) == childCount - 1;
        animation.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                if (isLast) {
                    postDelayed(new Runnable() {

                        @Override
                        public void run() {
                            onAllAnimationsEnd();
                        }
                    }, 0);
                }
            }
        });

        child.setAnimation(animation);
    }

    public boolean isExpanded() {
        return mExpanded;
    }

    public void setArc(float fromDegrees, float toDegrees) {
        if (mFromDegrees == fromDegrees && mToDegrees == toDegrees) {
            return;
        }

        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;

        requestLayout();
    }

    public void setChildSize(int size) {
        if (mChildSize == size || size < 0) {
            return;
        }

        mChildSize = size;

        requestLayout();
    }

    /**
     * switch between expansion and shrinkage
     * 
     * @param showAnimation
     */
    public void switchState(final boolean showAnimation) {
        if (showAnimation) {
            final int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                bindChildAnimation(getChildAt(i), i, 300);
            }
        }

        mExpanded = !mExpanded;

        if (!showAnimation) {
            requestLayout();
        }

        invalidate();
    }

    private void onAllAnimationsEnd() {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            getChildAt(i).clearAnimation();
        }

        requestLayout();
    }
}
like image 444
user1783209 Avatar asked Nov 16 '12 08:11

user1783209


1 Answers

As you can see in the following daCapricorn comment on a similar issue reported.

He gave details about the possible solution :

Set android:layout_alignParentBottom="true" and android:layout_alignParentLeft="true" in xml and compute the marginBottom and marginLeft (they should be negative) programmatically. marginBottom = (ArcMenu's height centerIcon's height)/2, marginLeft = (ArcMenu's width - centerIcon's width)/2.

The main idea here is to set the desired margins to negative values (my case is bottom right). I have managed to solve this by calculating the desired margins marginBottom = - ((ArcMenu's height centerIcon's height)/2), marginRight = -((ArcMenu's width - centerIcon's width)/2).

I did not do this inside onMeasure at the library code's ArcLayout.java , I did the following inside my activity.

In my activity's layout set the layout_alignParent as desired :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:arc="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <com.capricorn.ArcMenu
         android:layout_alignParentBottom="true"
         android:layout_alignParentRight="true"
         android:id="@+id/arc_menu"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         arc:childSize="@dimen/menuChildSize"
         arc:fromDegrees="180"
         arc:toDegrees="270" />

</RelativeLayout>

In my activity :

ArcMenu arcMenu; // the arc menu
FrameLayout controlLayout; // the frame layout of the control from library
int arcWidth, arcHeight; // arc menu measurments to be calculated , required for margins 
int controlLayoutWidth, controlLayoutHeight; // controlLayout measurments to be calculated , required for margins 
boolean isArcMeasureReady, isControlLayoutMeasureReady; // determine if measurements are ready if so apply the margins with the following runnable
Runnable runnable = new Runnable() {

    @Override
    public void run() {
        if (isArcMeasureReady && isControlLayoutMeasureReady) {
            RelativeLayout.LayoutParams params = (LayoutParams) arcMenu // your container LayoutParmas , mine is RelativeLayout
                    .getLayoutParams(); 
            int rightMargin = -((arcWidth - crossWidth) / 2);
            int bottomMargin = -((arcHeight - crossHeight) / 2);
            params.setMargins(0, 0, rightMargin, bottomMargin);
            arcMenu.setLayoutParams(params);
        }
    }
};

my onCreate :

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    isArcMeasureReady = isControlLayoutMeasureReady = false;
    controlLayout = (FrameLayout) findViewById(com.capricorn.R.id.control_layout);
    ... 

    ViewTreeObserver viewTreeObserverControlLayout = controlLayout.getViewTreeObserver();
    if (viewTreeObserverControlLayout.isAlive()) {
        viewTreeObserverControlLayout
                .addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        controlLayout.getViewTreeObserver()
                                .removeGlobalOnLayoutListener(this);
                        controlLayoutWidth = controlLayout.getWidth();
                        controlLayoutHeight = controlLayout.getHeight();
                        isControlLayoutMeasureReady = true;

                        runOnUiThread(runnable);

                    }
                });
    }

    ViewTreeObserver viewTreeObserver = arcMenu.getViewTreeObserver();
    if (viewTreeObserver.isAlive()) {
        viewTreeObserver
                .addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        arcMenu.getViewTreeObserver()
                                .removeGlobalOnLayoutListener(this);
                        arcWidth = arcMenu.getWidth();
                        arcHeight = arcMenu.getHeight();
                        isArcMeasureReady = true;

                        runOnUiThread(runnable);
                    }
                });
    }

I tested this on multiple devices and it works great because the calculation is dynamic.

Hope this helps enjoy the great widget from this guy daCapricorn

like image 168
EviatarS Avatar answered Oct 31 '22 03:10

EviatarS