private void InitWaterDropHolders(RectF bottleRect, RectF waterRect)
        {
            float bottleRadius         = bottleRect.Width() / 2.0f;
            float lowestWaterPointY    = waterRect.Top;
            float twoSidesInterval     = 0.2f * bottleRect.Width();
            float atLeastDelayDuration = 0.1f;

            float unitDuration        = 0.1f;
            float delayDurationRange  = 0.6f;
            int   radiusRandomRange   = MAX_WATER_DROP_RADIUS - MIN_WATER_DROP_RADIUS;
            float currentXRandomRange = bottleRect.Width() * 0.6f;

            for (int i = 0; i < DEFAULT_WATER_DROP_COUNT; i++)
            {
                WaterDropHolder waterDropHolder = new WaterDropHolder
                {
                    mRadius = MIN_WATER_DROP_RADIUS + mRandom.Next(radiusRandomRange),
                    mInitX  = bottleRect.Left + twoSidesInterval + (float)mRandom.NextDouble() * currentXRandomRange
                };
                waterDropHolder.mInitY         = lowestWaterPointY + waterDropHolder.mRadius / 2.0f;
                waterDropHolder.mRiseHeight    = GetMaxRiseHeight(bottleRadius, waterDropHolder.mRadius, waterDropHolder.mInitX - bottleRect.Left) * (0.2f + 0.8f * (float)mRandom.NextDouble());
                waterDropHolder.mDelayDuration = atLeastDelayDuration + (float)mRandom.NextDouble() * delayDurationRange;
                waterDropHolder.mDuration      = waterDropHolder.mRiseHeight / bottleRadius * unitDuration;

                mWaterDropHolders.Add(waterDropHolder);
            }
        }
        private Path CreateWaterPath(RectF waterRect, float progress)
        {
            Path path = new Path();

            path.MoveTo(waterRect.Left, waterRect.Top);

            //Similar to the way draw the bottle's Bottom sides
            float radius            = (waterRect.Width() - mStrokeWidth) / 2.0f;
            float CenterY           = waterRect.Bottom - 0.86f * radius;
            float bottleBottomWidth = waterRect.Width() / 2.0f;
            RectF bodyRect          = new RectF(waterRect.Left, CenterY - radius, waterRect.Right, CenterY + radius);

            path.AddArc(bodyRect, 187.5f, -67.5f);
            path.LineTo(waterRect.CenterX() - bottleBottomWidth / 2.0f, waterRect.Bottom);
            path.LineTo(waterRect.CenterX() + bottleBottomWidth / 2.0f, waterRect.Bottom);
            path.AddArc(bodyRect, 60, -67.5f);

            //draw the water waves
            float cubicXChangeSize = waterRect.Width() * 0.35f * progress;
            float cubicYChangeSize = waterRect.Height() * 1.2f * progress;

            path.CubicTo(waterRect.Left + waterRect.Width() * 0.80f - cubicXChangeSize, waterRect.Top - waterRect.Height() * 1.2f + cubicYChangeSize, waterRect.Left + waterRect.Width() * 0.55f - cubicXChangeSize, waterRect.Top - cubicYChangeSize, waterRect.Left, waterRect.Top - mStrokeWidth / 2.0f);

            path.LineTo(waterRect.Left, waterRect.Top);

            return(path);
        }
        protected internal override void ComputeRender(float renderProgress)
        {
            if (mCurrentBounds.Width() <= 0)
            {
                return;
            }

            RectF arcBounds = mCurrentBounds;

            //compute gas tube bounds
            mBottleBounds.Set(arcBounds.CenterX() - mBottleWidth / 2.0f, arcBounds.CenterY() - mBottleHeight / 2.0f, arcBounds.CenterX() + mBottleWidth / 2.0f, arcBounds.CenterY() + mBottleHeight / 2.0f);
            //compute pipe body bounds
            mWaterBounds.Set(mBottleBounds.Left + mStrokeWidth * 1.5f, mBottleBounds.Top + mWaterLowestPointToBottleneckDistance, mBottleBounds.Right - mStrokeWidth * 1.5f, mBottleBounds.Bottom - mStrokeWidth * 1.5f);

            //compute wave progress
            float totalWaveProgress   = renderProgress * mWaveCount;
            float currentWaveProgress = totalWaveProgress - ((int)totalWaveProgress);

            if (currentWaveProgress > 0.5f)
            {
                mProgress = 1.0f - MATERIAL_INTERPOLATOR.GetInterpolation((currentWaveProgress - 0.5f) * 2.0f);
            }
            else
            {
                mProgress = MATERIAL_INTERPOLATOR.GetInterpolation(currentWaveProgress * 2.0f);
            }

            //init water drop holders
            if (mWaterDropHolders.Count == 0)
            {
                InitWaterDropHolders(mBottleBounds, mWaterBounds);
            }

            //compute the location of these water drops
            foreach (WaterDropHolder waterDropHolder in mWaterDropHolders)
            {
                if (waterDropHolder.mDelayDuration < renderProgress && waterDropHolder.mDelayDuration + waterDropHolder.mDuration > renderProgress)
                {
                    float riseProgress = (renderProgress - waterDropHolder.mDelayDuration) / waterDropHolder.mDuration;
                    riseProgress = riseProgress < 0.5f ? riseProgress * 2.0f : 1.0f - (riseProgress - 0.5f) * 2.0f;
                    waterDropHolder.mCurrentY = waterDropHolder.mInitY - MATERIAL_INTERPOLATOR.GetInterpolation(riseProgress) * waterDropHolder.mRiseHeight;
                    waterDropHolder.mNeedDraw = true;
                }
                else
                {
                    waterDropHolder.mNeedDraw = false;
                }
            }

            //measure loading text
            mPaint.TextSize = mTextSize;
            mPaint.GetTextBounds(LOADING_TEXT, 0, LOADING_TEXT.Length, mLoadingBounds);
        }
        private Path CreateBottlePath(RectF bottleRect)
        {
            float bottleneckWidth            = bottleRect.Width() * 0.3f;
            float bottleneckHeight           = bottleRect.Height() * 0.415f;
            float bottleneckDecorationWidth  = bottleneckWidth * 1.1f;
            float bottleneckDecorationHeight = bottleneckHeight * 0.167f;

            Path path = new Path();

            //draw the Left side of the bottleneck decoration
            path.MoveTo(bottleRect.CenterX() - bottleneckDecorationWidth * 0.5f, bottleRect.Top);
            path.QuadTo(bottleRect.CenterX() - bottleneckDecorationWidth * 0.5f - bottleneckWidth * 0.15f, bottleRect.Top + bottleneckDecorationHeight * 0.5f, bottleRect.CenterX() - bottleneckWidth * 0.5f, bottleRect.Top + bottleneckDecorationHeight);
            path.LineTo(bottleRect.CenterX() - bottleneckWidth * 0.5f, bottleRect.Top + bottleneckHeight);

            //draw the Left side of the bottle's body
            float radius   = (bottleRect.Width() - mStrokeWidth) / 2.0f;
            float CenterY  = bottleRect.Bottom - 0.86f * radius;
            RectF bodyRect = new RectF(bottleRect.Left, CenterY - radius, bottleRect.Right, CenterY + radius);

            path.AddArc(bodyRect, 255, -135);

            //draw the Bottom of the bottle
            float bottleBottomWidth = bottleRect.Width() / 2.0f;

            path.LineTo(bottleRect.CenterX() - bottleBottomWidth / 2.0f, bottleRect.Bottom);
            path.LineTo(bottleRect.CenterX() + bottleBottomWidth / 2.0f, bottleRect.Bottom);

            //draw the Right side of the bottle's body
            path.AddArc(bodyRect, 60, -135);

            //draw the Right side of the bottleneck decoration
            path.LineTo(bottleRect.CenterX() + bottleneckWidth * 0.5f, bottleRect.Top + bottleneckDecorationHeight);
            path.QuadTo(bottleRect.CenterX() + bottleneckDecorationWidth * 0.5f + bottleneckWidth * 0.15f, bottleRect.Top + bottleneckDecorationHeight * 0.5f, bottleRect.CenterX() + bottleneckDecorationWidth * 0.5f, bottleRect.Top);

            return(path);
        }
        private Path CreateProgressPath(float progress, float circleRadius, RectF progressRect)
        {
            RectF arcProgressRect  = new RectF(progressRect.Left, progressRect.Top, progressRect.Left + circleRadius * 2, progressRect.Bottom);
            RectF rectProgressRect = null;

            float progressWidth     = progress * progressRect.Width();
            float progressModeWidth = mMode == MODE_LEAF_COUNT ? (float)mCurrentLeafCount / (float)LEAF_COUNT * progressRect.Width() : progress *progressRect.Width();

            float swipeAngle = DEGREE_180;

            //the Left half circle of the progressbar
            if (progressModeWidth < circleRadius)
            {
                swipeAngle = progressModeWidth / circleRadius * DEGREE_180;
            }

            //the center rect of the progressbar
            if (progressModeWidth < progressRect.Width() - circleRadius && progressModeWidth >= circleRadius)
            {
                rectProgressRect = new RectF(progressRect.Left + circleRadius, progressRect.Top, progressRect.Left + progressModeWidth, progressRect.Bottom);
            }

            //the Right half circle of the progressbar
            if (progressWidth >= progressRect.Width() - circleRadius)
            {
                rectProgressRect = new RectF(progressRect.Left + circleRadius, progressRect.Top, progressRect.Right - circleRadius, progressRect.Bottom);
                mScale           = (progressRect.Width() - progressWidth) / circleRadius;
            }

            //the Left of the Right half circle
            if (progressWidth < progressRect.Width() - circleRadius)
            {
                mRotation = (progressWidth / (progressRect.Width() - circleRadius)) * FULL_GROUP_ROTATION % DEGREE_360;

                RectF leafRect = new RectF(progressRect.Left + progressWidth, progressRect.Top, progressRect.Right - circleRadius, progressRect.Bottom);
                AddLeaf(progress, leafRect);
            }

            Path path = new Path();

            path.AddArc(arcProgressRect, DEGREE_180 - swipeAngle / 2, swipeAngle);

            if (rectProgressRect != null)
            {
                path.AddRect(rectProgressRect, Path.Direction.Cw);
            }

            return(path);
        }