package com.maxiee.heartbeat.common.cloudview; import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.util.Pair; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.RemoteViews; import android.widget.TextView; import com.maxiee.heartbeat.R; import java.util.List; /** * Created by maxiee on 15-6-24. */ @RemoteViews.RemoteView public class CloudView extends ViewGroup { private static final int MAX_SIZE = 70; private OnLabelClickListener mCallback; public interface OnLabelClickListener { void onClick(String label); } public CloudView(Context context) { super(context); } public CloudView(Context context, AttributeSet attrs) { super(context, attrs); } public CloudView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void setOnLabelClickListener(OnLabelClickListener callback) { mCallback = callback; } public void addLabels(List<Pair<String, Integer>> labels) { removeAllViews(); if (labels == null) { return; } float maxFreq = computeMaxFreq(labels); final TypedValue accentValue = new TypedValue(); getContext().getTheme().resolveAttribute(R.attr.colorAccent, accentValue, true); int accentColor = accentValue.data; final TypedValue grayValue = new TypedValue(); getContext().getTheme().resolveAttribute(R.attr.colorPrimary, grayValue, true); int grayColor = grayValue.data; float redStep = (Color.red(accentColor) - Color.red(grayColor)) / maxFreq; float greenStep = (Color.green(accentColor) - Color.green(grayColor)) / maxFreq; float blueStep = (Color.blue(accentColor) - Color.blue(grayColor)) / maxFreq; for (final Pair<String, Integer> label: labels) { TextView tagView = new TextView(getContext()); tagView.setText(label.first); tagView.setTextSize(label.second / maxFreq * MAX_SIZE); tagView.setTextColor( Color.rgb( (int) (Color.red(grayColor) + redStep * label.second), (int) (Color.green(grayColor) + greenStep * label.second), (int) (Color.blue(grayColor) + blueStep * label.second) ) ); LayoutParams layoutParams = new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT ); layoutParams.setMargins(20, 5, 20, 5); tagView.setLayoutParams(layoutParams); tagView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mCallback != null) { mCallback.onClick(label.first); } } }); addView(tagView); } } private float computeMaxFreq(List<Pair<String, Integer>> labels) { float maxFreq = 1; for (Pair<String, Integer> label: labels) { if (label.second > maxFreq) { maxFreq = label.second; } } return maxFreq; } @Override public boolean shouldDelayChildPressedState() { return false; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int mViewGroupWidth = getMeasuredWidth(); int mViewGroupHeight = getMeasuredHeight(); int heightMax = 0; int mPainterPosX = l; int mPainterPosY = t; int childCount = getChildCount(); for (int i=0; i<childCount; i++) { View childView = getChildAt(i); int width = childView.getMeasuredWidth(); int height = childView.getMeasuredHeight(); LayoutParams layoutParams = (LayoutParams) childView.getLayoutParams(); if (mPainterPosX + layoutParams.leftMargin + width + layoutParams.rightMargin > mViewGroupWidth) { mPainterPosX = l; mPainterPosY += heightMax; heightMax = 0; } childView.layout( mPainterPosX + layoutParams.leftMargin, mPainterPosY + layoutParams.topMargin, mPainterPosX + width + layoutParams.rightMargin, mPainterPosY + height + layoutParams.bottomMargin ); mPainterPosX += width + layoutParams.leftMargin + layoutParams.rightMargin; if (height > heightMax) { heightMax = height; } } } @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new ViewGroup.LayoutParams(getContext(), attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); int start = 0; int currentLineWidth = 0; int currentLineHeight = 0; int totalHeight = 0; int totalWeight = 0; for (int i=0; i<count; i++) { final View child = getChildAt(i); measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (i==0) { // first one start = child.getLeft(); currentLineWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; currentLineHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; } if (child.getLeft() != start) { // not the last currentLineHeight = Math.max( currentLineHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); currentLineWidth += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } else { // the last one totalHeight += currentLineHeight; totalWeight= Math.max(currentLineWidth, totalWeight); currentLineWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; currentLineHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; } } setMeasuredDimension(resolveSize(totalWeight, widthMeasureSpec), resolveSize(totalHeight, heightMeasureSpec)); } public static class LayoutParams extends MarginLayoutParams { public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } public LayoutParams(int width, int height) { super(width, height); } public LayoutParams(MarginLayoutParams source) { super(source); } } }