From 5eacb5dfec251df164a1efd539d5b7862f75f0de Mon Sep 17 00:00:00 2001 From: jmAndroid <jay@huangjie.name> Date: Mon, 25 Feb 2019 13:53:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=8A=9F=E8=83=BD,v1.0?= =?UTF-8?q?=E7=89=88=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 3 + .../jie/com/funnel/BaseFunnelActivity.java | 24 +++ .../com/funnel/CustomHalfWidthActivity.java | 42 +++++ .../jie/com/funnel/CustomLabelActivity.java | 45 +++++ .../java/jie/com/funnel/DefaultActivity.java | 16 ++ .../main/java/jie/com/funnel/FunnelData.java | 63 ++++++- .../java/jie/com/funnel/MainActivity.java | 50 ++--- ...activity_main.xml => activity_default.xml} | 14 +- ...tomLabel.java => CustomLabelCallback.java} | 2 +- .../java/jie/com/funnellib/FunnelView.java | 171 +++++++++++------- .../jie/com/funnellib/HalfWidthCallback.java | 16 ++ .../java/jie/com/funnellib/IFunnelData.java | 13 +- .../src/main/java/jie/com/funnellib/Util.java | 24 ++- 13 files changed, 369 insertions(+), 114 deletions(-) create mode 100644 app/src/main/java/jie/com/funnel/BaseFunnelActivity.java create mode 100644 app/src/main/java/jie/com/funnel/CustomHalfWidthActivity.java create mode 100644 app/src/main/java/jie/com/funnel/CustomLabelActivity.java create mode 100644 app/src/main/java/jie/com/funnel/DefaultActivity.java rename app/src/main/res/layout/{activity_main.xml => activity_default.xml} (53%) rename funnellib/src/main/java/jie/com/funnellib/{CustomLabel.java => CustomLabelCallback.java} (93%) create mode 100644 funnellib/src/main/java/jie/com/funnellib/HalfWidthCallback.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index da3715e..1a6e670 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,6 +16,9 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + <activity android:name=".DefaultActivity" /> + <activity android:name=".CustomLabelActivity" /> + <activity android:name=".CustomHalfWidthActivity" /> </application> </manifest> \ No newline at end of file diff --git a/app/src/main/java/jie/com/funnel/BaseFunnelActivity.java b/app/src/main/java/jie/com/funnel/BaseFunnelActivity.java new file mode 100644 index 0000000..f1ac440 --- /dev/null +++ b/app/src/main/java/jie/com/funnel/BaseFunnelActivity.java @@ -0,0 +1,24 @@ +package jie.com.funnel; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; + +import jie.com.funnellib.FunnelView; + +/** + * Created by hj on 2019/2/25. + * 说明: + */ +public abstract class BaseFunnelActivity extends AppCompatActivity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_default); + FunnelView funnelVie = findViewById(R.id.funnelView); + initEvent(funnelVie); + } + + abstract void initEvent(FunnelView funnelView); +} diff --git a/app/src/main/java/jie/com/funnel/CustomHalfWidthActivity.java b/app/src/main/java/jie/com/funnel/CustomHalfWidthActivity.java new file mode 100644 index 0000000..76eeeb0 --- /dev/null +++ b/app/src/main/java/jie/com/funnel/CustomHalfWidthActivity.java @@ -0,0 +1,42 @@ +package jie.com.funnel; + +import android.util.TypedValue; + +import jie.com.funnellib.FunnelView; +import jie.com.funnellib.HalfWidthCallback; + +/** + * Created by hj on 2019/2/25. + * 说明:自定义宽度策略 + */ +public class CustomHalfWidthActivity extends BaseFunnelActivity { + + @Override + void initEvent(FunnelView funnelView) { + /** + * 自定义宽度策略,也就是漏斗每一层宽度增加多少,这都是可以自定义的,这样有利于适配的灵活性,也可以自定义出 + * 很多的效果出来 + * 注意事项:绘制是从下往上绘制的,halfWidth返回的当前的下面那个漏斗的宽度,需要注意一下 + * + */ + funnelView.setChartData(FunnelData.getTenCountData(), new HalfWidthCallback() { + @Override + public float getHalfStrategy(float halfWidth, int count, int i) { + /** + * 这里定义的策略是前4个宽度不变,后面的逐渐增加10dp,所以呈现了一个真正的漏斗形状 + */ + if (i <= 3) { + halfWidth = dp2px(5); + return halfWidth; + } else { + halfWidth += dp2px(10); + return halfWidth; + } + } + }); + } + + private float dp2px(int dip) { + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, this.getResources().getDisplayMetrics()); + } +} diff --git a/app/src/main/java/jie/com/funnel/CustomLabelActivity.java b/app/src/main/java/jie/com/funnel/CustomLabelActivity.java new file mode 100644 index 0000000..bea4e34 --- /dev/null +++ b/app/src/main/java/jie/com/funnel/CustomLabelActivity.java @@ -0,0 +1,45 @@ +package jie.com.funnel; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; + +import java.util.ArrayList; +import java.util.List; + +import jie.com.funnellib.CustomLabelCallback; +import jie.com.funnellib.FunnelView; +import jie.com.funnellib.Util; + +/** + * Created by hj on 2019/2/25. + * 说明:此Activity演示自定义描述文字 + */ +public class CustomLabelActivity extends BaseFunnelActivity { + + @Override + void initEvent(FunnelView funnelView) { + final List<FunnelData> data = FunnelData.getFourCountData(); + + funnelView.addCustomLabelCallback(new CustomLabelCallback() { + @Override + public void drawText(Canvas canvas, Paint mPaintLabel, float labelX, float labelY, int index) { + FunnelData funnelData = data.get(index); + //先画前面的文字 + mPaintLabel.setColor(funnelData.color); + mPaintLabel.setFakeBoldText(false); + canvas.drawText(funnelData.getLabel()+":", labelX, labelY, mPaintLabel); + //计算前面文字的长度 + float labelWidth = Util.getTextWidth(mPaintLabel,funnelData.getLabel()+":"); + mPaintLabel.setColor(Color.parseColor("#333333")); + mPaintLabel.setFakeBoldText(true); + //画后面的文字 + canvas.drawText(funnelData.num+"个", labelX + labelWidth, labelY, mPaintLabel); + } + }); + funnelView.setChartData(data); + } +} diff --git a/app/src/main/java/jie/com/funnel/DefaultActivity.java b/app/src/main/java/jie/com/funnel/DefaultActivity.java new file mode 100644 index 0000000..0b74429 --- /dev/null +++ b/app/src/main/java/jie/com/funnel/DefaultActivity.java @@ -0,0 +1,16 @@ +package jie.com.funnel; + + +import jie.com.funnellib.FunnelView; + +/** + * Created by hj on 2019/2/25. + * 说明:使用默认方式创建一个漏斗 + */ +public class DefaultActivity extends BaseFunnelActivity { + + @Override + void initEvent(FunnelView funnelView) { + funnelView.setChartData(FunnelData.getTenCountData()); + } +} diff --git a/app/src/main/java/jie/com/funnel/FunnelData.java b/app/src/main/java/jie/com/funnel/FunnelData.java index 4df3412..24dbe8d 100644 --- a/app/src/main/java/jie/com/funnel/FunnelData.java +++ b/app/src/main/java/jie/com/funnel/FunnelData.java @@ -1,5 +1,10 @@ package jie.com.funnel; +import android.graphics.Color; + +import java.util.ArrayList; +import java.util.List; + import jie.com.funnellib.IFunnelData; /** @@ -7,14 +12,10 @@ * 说明: */ public class FunnelData implements IFunnelData { - public String value; public String label; public int color; - @Override - public String getValue() { - return value; - } + public String num; @Override public int getColor() { @@ -25,4 +26,56 @@ public int getColor() { public String getLabel() { return label; } + + + //-----------------------------测试数据-------------------------------------------------------------- + private static int[] colors = new int[]{ + Color.parseColor("#FF5656"), Color.parseColor("#FF854B"), + Color.parseColor("#FFB240"), Color.parseColor("#FFEC3D"), + Color.parseColor("#4DD2F9"), Color.parseColor("#52B5FF"), + Color.parseColor("#5882FF"), Color.parseColor("#5959FF"), + Color.parseColor("#8359FF"), Color.parseColor("#AC59FF") + }; + + private static String[] labels = new String[]{ + "Android", "ios", + "php", "c", + "c++", "python", + "golang", "java", + "javascript", ".net" + }; + + + private static int[] fourColors = new int[]{ + Color.parseColor("#FF5D5D"), Color.parseColor("#FFB240"), + Color.parseColor("#52B5FF"), Color.parseColor("#5882FF"), + }; + + private static String[] fourLabel = new String[]{ + "数学", "语文", "物理", "化学" + }; + + public static List<FunnelData> getFourCountData() { + List<FunnelData> data = new ArrayList<>(); + for (int i = 0; i < fourLabel.length; i++) { + FunnelData funnelData = new FunnelData(); + funnelData.label = fourLabel[i]; + funnelData.color = fourColors[i]; + funnelData.num = String.valueOf(i); + data.add(funnelData); + } + return data; + } + + public static List<FunnelData> getTenCountData() { + List<FunnelData> data = new ArrayList<>(); + for (int i = labels.length - 1; i >= 0; i--) { + FunnelData funnelData = new FunnelData(); + funnelData.label = labels[i]; + funnelData.color = colors[i]; + funnelData.num = String.valueOf(i); + data.add(funnelData); + } + return data; + } } diff --git a/app/src/main/java/jie/com/funnel/MainActivity.java b/app/src/main/java/jie/com/funnel/MainActivity.java index a579371..c157265 100644 --- a/app/src/main/java/jie/com/funnel/MainActivity.java +++ b/app/src/main/java/jie/com/funnel/MainActivity.java @@ -1,9 +1,15 @@ package jie.com.funnel; +import android.app.ListActivity; +import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.SimpleAdapter; import java.util.ArrayList; import java.util.List; @@ -15,34 +21,34 @@ * Created by hj on 2019/2/22. * 说明: */ -public class MainActivity extends AppCompatActivity { +public class MainActivity extends ListActivity { - private int[] colors = new int[]{ - Color.parseColor("#FF5656"), Color.parseColor("#FF854B"), - Color.parseColor("#FFB240"), Color.parseColor("#FFEC3D"), - Color.parseColor("#4DD2F9"), Color.parseColor("#52B5FF"), - Color.parseColor("#5882FF"), Color.parseColor("#5959FF"), - Color.parseColor("#8359FF"), Color.parseColor("#AC59FF") - }; - - private int[] fourColors = new int[]{ - Color.parseColor("#FF5D5D"), Color.parseColor("#FFB240"), - Color.parseColor("#52B5FF"), Color.parseColor("#5882FF"), + private final String[] data = new String[]{ + "使用默认方式(Use default mode)", + "自定义描述文字(Custom Description Text)", + "使用自定义宽度策略(Use custom width policy)", }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - FunnelView funnelView = findViewById(R.id.funnel); - List<IFunnelData> data = new ArrayList<>(); - for (int i = 0; i < 4; i++) { - FunnelData entity = new FunnelData(); - entity.value = "A"; - entity.color = fourColors[i]; - entity.label = i+""; - data.add(entity); + ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, + data); + setListAdapter(adapter); + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + switch (position) { + case 0: + startActivity(new Intent(this, DefaultActivity.class)); + break; + case 1: + startActivity(new Intent(this, CustomLabelActivity.class)); + break; + case 2: + startActivity(new Intent(this,CustomHalfWidthActivity.class)); + break; } - funnelView.setChartData(data); } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_default.xml similarity index 53% rename from app/src/main/res/layout/activity_main.xml rename to app/src/main/res/layout/activity_default.xml index 8a66acc..b84e6ae 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_default.xml @@ -4,13 +4,11 @@ android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> - <jie.com.funnellib.FunnelView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:id="@+id/funnel" - android:paddingLeft="10dp" - android:paddingTop="10dp" - android:background="#e4ebe8" - /> + <jie.com.funnellib.FunnelView + android:id="@+id/funnelView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="10dp" + android:paddingTop="10dp" /> </LinearLayout> \ No newline at end of file diff --git a/funnellib/src/main/java/jie/com/funnellib/CustomLabel.java b/funnellib/src/main/java/jie/com/funnellib/CustomLabelCallback.java similarity index 93% rename from funnellib/src/main/java/jie/com/funnellib/CustomLabel.java rename to funnellib/src/main/java/jie/com/funnellib/CustomLabelCallback.java index 58c726c..97f481e 100644 --- a/funnellib/src/main/java/jie/com/funnellib/CustomLabel.java +++ b/funnellib/src/main/java/jie/com/funnellib/CustomLabelCallback.java @@ -7,7 +7,7 @@ * Created by hj on 2019/2/22. * 说明:开放自定义描述绘制画笔 */ -public interface CustomLabel { +public interface CustomLabelCallback { /** * 循环绘制线后面的文字 * @param canvas 画布 diff --git a/funnellib/src/main/java/jie/com/funnellib/FunnelView.java b/funnellib/src/main/java/jie/com/funnellib/FunnelView.java index c1e4856..627aff6 100644 --- a/funnellib/src/main/java/jie/com/funnellib/FunnelView.java +++ b/funnellib/src/main/java/jie/com/funnellib/FunnelView.java @@ -22,7 +22,9 @@ /** * Created by hj on 2018/11/23. - * 说明:漏斗View + * 说明:漏斗View,可自定义宽度,颜色,高度,描述文字,线宽,线颜色等... + * 详细操作请阅读README.md + * github: https://github.com/Jay-huangjie/FunnelView */ public class FunnelView extends View { private static final String TAG = "FunnelChart"; @@ -55,11 +57,8 @@ public class FunnelView extends View { private float mLastLineOffset; //最底部从中心点向两边的偏移量 private float mTotalHeight; //单个梯形的目标高度 private int count; //漏斗的个数 - private float mPlotRight; - private float mPlotLeft; - private float mPlotBottom; - private float mPlotTop; - + private float mPlotBottom; //底部坐标 + private boolean EXACTLY; //是否是精确高度 /* * 中心点坐标,绘制是从下往上,这个坐标是最底部那跟线的中心点 * 最后一根线的长度= mLastLineOffset*2 @@ -75,13 +74,18 @@ public class FunnelView extends View { * */ private float mPlotWidth; - //最顶部的线的宽度 - private float mTopMaxLineWidth; + //最长的线的宽度的一半 + private float mTopMaxLineHalf; /* * 自定义绘制描述文字接口 * */ - private CustomLabel mCustomLabel; + private CustomLabelCallback mCustomLabelCallback; + + /* + * 自定义漏斗宽度变化策略 + * */ + private HalfWidthCallback mHalfWidthCallback; /* * 漏斗之间线的颜色 @@ -107,6 +111,11 @@ public class FunnelView extends View { * */ private float mLabelSize; + /* + * 宽度策略数据容器 + * */ + private float[] halfArrays; + public FunnelView(Context context) { super(context); initView(context, null); @@ -142,13 +151,6 @@ private void initView(Context context, AttributeSet attributeSet) { } - public void setChartData(@NonNull List<IFunnelData> chartData) { - this.mDataSet = chartData; - count = mDataSet.size(); - mTopMaxLineWidth = mLastLineOffset + getHalfWidthOffset() * count; - invalidate(); - } - private void chartRender() { mPaintLabel = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -174,9 +176,7 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { protected void onDraw(Canvas canvas) { try { canvas.save(); - //计算主图表区范围 calcPlotRange(); - //绘制图表 renderPlot(canvas); canvas.restore(); } catch (Exception e) { @@ -189,7 +189,7 @@ private void renderPlot(Canvas canvas) { Log.e(TAG, "FunnelView=>未设置数据源!"); return; } - float funnelHeight = mPlotHeight / count; + float funnelHeight = EXACTLY ? mPlotHeight / count : mTotalHeight; float cx = mCenterX; renderPlotDesc(canvas, cx, funnelHeight); } @@ -214,28 +214,29 @@ private int measureWidth(int measureSpec) { } private int measureHeight(int measureSpec) { - int result = (int) mTotalHeight * count; + int result = (int) (mTotalHeight * count + mFunnelLineStoke * (count - 1)); int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { //fill_parent result = specSize; + EXACTLY = true; } return result; } /** - * 计算图的显示范围,依屏幕px值来计算. + * 计算一些关键数据 */ private void calcPlotRange() { mPlotBottom = mBottom - getPaddingBottom(); - mPlotTop = getPaddingTop(); - mPlotLeft = getPaddingLeft(); - mPlotRight = mRight - getPaddingRight(); + float mPlotTop = getPaddingTop(); + float mPlotLeft = getPaddingLeft(); + float mPlotRight = mRight - getPaddingRight(); mPlotWidth = Math.abs(mPlotRight - mPlotLeft); mPlotHeight = Math.abs(mPlotBottom - mPlotTop); - mCenterX = (int) mTopMaxLineWidth + mPlotLeft; + mCenterX = (int) mTopMaxLineHalf + mPlotLeft; } /** @@ -259,14 +260,11 @@ private void renderPlotDesc(Canvas canvas, float cx, float funnelHeight) { int count = mDataSet.size(); float halfWidth = 0.f; //梯形的半径 float bottomY; - PointF pStart = new PointF(); PointF pStop = new PointF(); - pStart.x = cx - mPlotWidth / 2; pStop.x = cx + mPlotWidth / 2; pStart.y = pStop.y = mPlotBottom; - float labelY = 0.f; Path path = new Path(); for (int i = 0; i < count; i++) { @@ -274,33 +272,23 @@ private void renderPlotDesc(Canvas canvas, float cx, float funnelHeight) { path.reset(); if (i == 0) { //画底部的线,从左下角开始绘制 path.moveTo(cx - mLastLineOffset, mPlotBottom); - //底部线默认长度为100 + //底部线默认长度为80 path.lineTo(cx + mLastLineOffset, mPlotBottom); } else { path.moveTo(pStart.x, pStart.y); path.lineTo(pStop.x, pStop.y); } - //根据数量来调整倾斜角度,如果需要实现别的倾斜效果只需调整下面的算法 - if (count <= 4) { - halfWidth += dip2px(mContext, 17); - } else if (count <= 6) { - halfWidth += dip2px(mContext, 13); - } else if (count <= 8) { - halfWidth += dip2px(mContext, 10); - } else if (count <= 10) { - halfWidth += dip2px(mContext, 7); + //根据数量来调整倾斜角度,如果需要实现别的倾斜效果只需实现HalfWidthCallback接口 + if (mHalfWidthCallback == null) { + halfWidth += getDefaultHalfWidthOffset(); } else { - halfWidth += dip2px(mContext, 5); + halfWidth = halfArrays[i]; } bottomY = sub(mPlotBottom, i * funnelHeight); - labelY = bottomY - funnelHeight / 2; - pStart.x = cx - mLastLineOffset - halfWidth; pStart.y = bottomY - funnelHeight; - pStop.x = cx + mLastLineOffset + halfWidth; - Log.i("HJ", pStop.x + "--cx:" + mLastLineOffset + "--halfWidth:" + halfWidth); pStop.y = bottomY - funnelHeight; path.lineTo(pStop.x, pStop.y); //画右边的线 path.lineTo(pStart.x, pStart.y); //画左边的线 @@ -314,21 +302,22 @@ private void renderPlotDesc(Canvas canvas, float cx, float funnelHeight) { } } - - private float getHalfWidthOffset() { - if (count <= 4) { - return dip2px(mContext, 17); - } else if (count <= 6) { - return dip2px(mContext, 13); - } else if (count <= 8) { - return dip2px(mContext, 10); - } else if (count <= 10) { - return dip2px(mContext, 7); + //画线和字 + private void renderLabels(Canvas canvas, IFunnelData data, float cx, float y, int color, int halfWidth, int i) { + if (data == null) return; + mPaintLabelLine.setColor(color); + float lineX = cx + halfWidth + mLineWidth; + canvas.drawLine(cx, y, lineX, y, mPaintLabelLine); + float labelX = lineX + mLineTextSpace; + float labelY = y + getPaintFontHeight(mPaintLabel) / 3; + if (mCustomLabelCallback == null) { + canvas.drawText(data.getLabel(), labelX, labelY, mPaintLabel); } else { - return dip2px(mContext, 5); + mCustomLabelCallback.drawText(canvas, mPaintLabel, labelX, labelY, i); } } + /* * 设置线的宽度 * */ @@ -346,25 +335,67 @@ public void setLineTextSpace(float mLineTextSpace) { /* * 自定义描述绘制 * */ - public void addCustomDrawLabel(CustomLabel iCustomLabel) { - this.mCustomLabel = iCustomLabel; + public void addCustomLabelCallback(CustomLabelCallback iCustomLabelCallback) { + this.mCustomLabelCallback = iCustomLabelCallback; } - //画线和字 - private void renderLabels(Canvas canvas, IFunnelData data, float cx, float y, int color, int halfWidth, int i) { - if (data == null) return; - mPaintLabelLine.setColor(color); - float lineX = cx + halfWidth + mLineWidth; - canvas.drawLine(cx, y, lineX, y, mPaintLabelLine); - float labelX = lineX + mLineTextSpace; - float labelY = y + getPaintFontHeight(mPaintLabel) / 3; - if (mCustomLabel == null) { - canvas.drawText(data.getLabel(), labelX, labelY, mPaintLabel); -// float labelWidth = DrawHelper.getInstance().getTextWidth(mPaintLabel, data.getLabel()); -// setNumUi(); -// canvas.drawText(data.getNumUnit(), labelX + labelWidth, labelY, mPaintLabel); + /** + * 设置数据源 + * + * @param chartData 数据源 + */ + public <T extends IFunnelData> void setChartData(@NonNull List<T> chartData) { + setChartData(chartData, null); + } + + + /** + * 设置数据源及宽度策略 + * + * @param chartData 数据源 + * @param callback 宽度策略回调 + */ + public <T extends IFunnelData> void setChartData(@NonNull List<T> chartData, HalfWidthCallback callback) { + this.mDataSet = (List<IFunnelData>) chartData; + this.mHalfWidthCallback = callback; + count = mDataSet.size(); + if (callback == null) { + mTopMaxLineHalf = mLastLineOffset + getDefaultHalfWidthOffset() * count; } else { - mCustomLabel.drawText(canvas, mPaintLabel, labelX, labelY, i); + halfArrays = new float[count]; + float max = 0; + float halfWidth = 0; + //将所有的宽度数据组装进数组中 + for (int i = 0; i < count; i++) { + halfWidth = callback.getHalfStrategy(halfWidth, count, i); + halfArrays[i] = halfWidth; + } + //找出其中的最大值,此值也就是漏斗的最大宽度(不包括线和描述文字) + for (float value : halfArrays) { + if (max < value) { + max = value; + } + } + mTopMaxLineHalf = max + mLastLineOffset; + } + invalidate(); + } + + /* + * 默认漏斗宽度变化策略 + * */ + private float getDefaultHalfWidthOffset() { + if (count <= 4) { + return dip2px(mContext, 17); + } else if (count <= 6) { + return dip2px(mContext, 13); + } else if (count <= 8) { + return dip2px(mContext, 10); + } else if (count <= 10) { + return dip2px(mContext, 7); + } else { + return dip2px(mContext, 5); } } + } diff --git a/funnellib/src/main/java/jie/com/funnellib/HalfWidthCallback.java b/funnellib/src/main/java/jie/com/funnellib/HalfWidthCallback.java new file mode 100644 index 0000000..e41e47f --- /dev/null +++ b/funnellib/src/main/java/jie/com/funnellib/HalfWidthCallback.java @@ -0,0 +1,16 @@ +package jie.com.funnellib; + +/** + * Created by hj on 2019/2/25. + * 说明:自定义漏斗宽度变化策略 + */ +public interface HalfWidthCallback { + /** + * 自定义漏斗宽度变化策略 + * @param halfWidth 上一个梯形的宽度,第一个为0 + * @param count 漏斗梯形个数 + * @param i 梯形下标 + * @return 当前梯形的宽度,单位:PX + */ + float getHalfStrategy(float halfWidth,int count,int i); +} diff --git a/funnellib/src/main/java/jie/com/funnellib/IFunnelData.java b/funnellib/src/main/java/jie/com/funnellib/IFunnelData.java index a346891..758d347 100644 --- a/funnellib/src/main/java/jie/com/funnellib/IFunnelData.java +++ b/funnellib/src/main/java/jie/com/funnellib/IFunnelData.java @@ -2,10 +2,19 @@ /** * Created by hj on 2019/2/22. - * 说明: + * 说明:获取漏斗数据源接口 */ public interface IFunnelData { - String getValue(); + + /** + * 颜色 + * @return color + */ int getColor(); + + /** + * 描述 + * @return string + */ String getLabel(); } diff --git a/funnellib/src/main/java/jie/com/funnellib/Util.java b/funnellib/src/main/java/jie/com/funnellib/Util.java index 5e3e9bd..77c289f 100644 --- a/funnellib/src/main/java/jie/com/funnellib/Util.java +++ b/funnellib/src/main/java/jie/com/funnellib/Util.java @@ -11,18 +11,18 @@ * Created by hj on 2019/2/22. * 说明: */ -class Util { +public class Util { /** * convert sp to its equivalent px * <p> * 将sp转换为px */ - static float sp2px(Context context, float spValue) { + public static float sp2px(Context context, float spValue) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue,context.getResources().getDisplayMetrics()); } /** dip转换px */ - static float dip2px(Context context,int dip) { + public static float dip2px(Context context,int dip) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,context.getResources().getDisplayMetrics()); } @@ -30,7 +30,7 @@ static float dip2px(Context context,int dip) { /* * 禁止硬件加速 * */ - static void disableHardwareAccelerated(View view) { + public static void disableHardwareAccelerated(View view) { if (view == null) { return; } @@ -46,12 +46,24 @@ static void disableHardwareAccelerated(View view) { * @param paint 画笔 * @return 高度 */ - static float getPaintFontHeight(Paint paint) + public static float getPaintFontHeight(Paint paint) { Paint.FontMetrics fm = paint.getFontMetrics(); return (float) Math.ceil(fm.descent - fm.ascent); } + /** + * 得到一段文本的宽度 + * @param paint 画笔 + * @param str 文本 + * @return 文本宽度 + */ + public static float getTextWidth(Paint paint, String str) + { + if(str.length() == 0) return 0.0f; + return paint.measureText(str, 0, str.length()); + } + /** * 减法运算 * @@ -59,7 +71,7 @@ static float getPaintFontHeight(Paint paint) * @param v2 参数2 * @return 运算结果 */ - static float sub(float v1, float v2) { + public static float sub(float v1, float v2) { BigDecimal bgNum1 = new BigDecimal(Float.toString(v1)); BigDecimal bgNum2 = new BigDecimal(Float.toString(v2)); return bgNum1.subtract(bgNum2).floatValue();