/* * Copyright 2015 chenupt * Copyright 2015 LuckyJayce * * 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. */ package com.yuyh.library.view.viewpager.indicator.slidebar; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.view.View; public class SpringBar extends View implements ScrollBar { private int tabWidth; private Paint paint; private Path path; private Point foot; private Point head; private float radiusMax; private float radiusMin; private float radiusOffset; private float acceleration = 0.5f; private float headMoveOffset = 0.6f; private float footMoveOffset = 1 - headMoveOffset; private float maxRadiusPercent; private float minRadiusPercent; public SpringBar(Context context, int springColor) { this(context, springColor, 0.9f, 0.35f); } public SpringBar(Context context, int springColor, float maxRadiusPercent, float minRadiusPercent) { super(context); this.maxRadiusPercent = maxRadiusPercent; this.minRadiusPercent = minRadiusPercent; foot = new Point(); head = new Point(); path = new Path(); paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setStrokeWidth(1); paint.setColor(springColor); } @Override public int getHeight(int tabHeight) { int half = tabHeight / 2; foot.setY(half); head.setY(half); radiusMax = half * maxRadiusPercent; radiusMin = half * minRadiusPercent; radiusOffset = radiusMax - radiusMin; return tabHeight; } @Override public int getWidth(int tabWidth) { this.tabWidth = tabWidth; if (positionOffset < 0.02f || positionOffset > 0.98f) { onPageScrolled(0, 0, 0); } return tabWidth + tabWidth / 2; } @Override public View getSlideView() { return this; } @Override public Gravity getGravity() { return Gravity.CENTENT_BACKGROUND; } private float positionOffset; @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { this.positionOffset = positionOffset; if (positionOffset < 0.02f || positionOffset > 0.98f) { head.setX(getOffsetX(0)); foot.setX(getOffsetX(0)); head.setRadius(radiusMax); foot.setRadius(radiusMax); } else { float radiusOffsetHead = 0.5f; if (positionOffset < radiusOffsetHead) { head.setRadius(radiusMin); } else { head.setRadius(((positionOffset - radiusOffsetHead) / (1 - radiusOffsetHead) * radiusOffset + radiusMin)); } float radiusOffsetFoot = 0.5f; if (positionOffset < radiusOffsetFoot) { foot.setRadius((1 - positionOffset / radiusOffsetFoot) * radiusOffset + radiusMin); } else { foot.setRadius(radiusMin); } float headX = 0f; if (positionOffset > headMoveOffset) { float positionOffsetTemp = (positionOffset - headMoveOffset) / (1 - headMoveOffset); headX = (float) ((Math.atan(positionOffsetTemp * acceleration * 2 - acceleration) + (Math.atan(acceleration))) / (2 * (Math .atan(acceleration)))); } // x head.setX(getOffsetX(positionOffset) - headX * getPositionDistance(position)); float footX = 1f; if (positionOffset < footMoveOffset) { float positionOffsetTemp = positionOffset / footMoveOffset; footX = (float) ((Math.atan(positionOffsetTemp * acceleration * 2 - acceleration) + (Math.atan(acceleration))) / (2 * (Math .atan(acceleration)))); } foot.setX(getOffsetX(positionOffset) - footX * getPositionDistance(position)); } } private float getOffsetX(float positionOffset) { return tabWidth + tabWidth / 2 - tabWidth * (1 - positionOffset) + tabWidth / 4.0f; } private float getPositionDistance(int position) { return tabWidth; } @Override protected void onDraw(Canvas canvas) { makePath(); canvas.drawColor(Color.TRANSPARENT); // canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.OVERLAY); canvas.drawPath(path, paint); canvas.drawCircle(head.getX(), head.getY(), head.getRadius(), paint); canvas.drawCircle(foot.getX(), foot.getY(), foot.getRadius(), paint); super.onDraw(canvas); } private void makePath() { float headOffsetX = (float) (foot.getRadius() * Math.sin(Math.atan((head.getY() - foot.getY()) / (head.getX() - foot.getX())))); float headOffsetY = (float) (foot.getRadius() * Math.cos(Math.atan((head.getY() - foot.getY()) / (head.getX() - foot.getX())))); float footOffsetX = (float) (head.getRadius() * Math.sin(Math.atan((head.getY() - foot.getY()) / (head.getX() - foot.getX())))); float footOffsetY = (float) (head.getRadius() * Math.cos(Math.atan((head.getY() - foot.getY()) / (head.getX() - foot.getX())))); float x1 = foot.getX() - headOffsetX; float y1 = foot.getY() + headOffsetY; float x2 = foot.getX() + headOffsetX; float y2 = foot.getY() - headOffsetY; float x3 = head.getX() - footOffsetX; float y3 = head.getY() + footOffsetY; float x4 = head.getX() + footOffsetX; float y4 = head.getY() - footOffsetY; float anchorX = (head.getX() + foot.getX()) / 2; float anchorY = (head.getY() + foot.getY()) / 2; path.reset(); path.moveTo(x1, y1); path.quadTo(anchorX, anchorY, x3, y3); path.lineTo(x4, y4); path.quadTo(anchorX, anchorY, x2, y2); path.lineTo(x1, y1); } private class Point { private float x; private float y; private float radius; public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; } public float getRadius() { return radius; } public void setRadius(float radius) { this.radius = radius; } } }