package v2.simpleUi.customViews; import java.util.ArrayList; import java.util.List; import v2.simpleUi.util.ColorCollections; import v2.simpleUi.util.IO; import v2.simpleUi.util.ImageTransform; import v2.simpleUi.util.NameGenerator; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Paint.Style; import android.graphics.Shader; import android.text.Layout.Alignment; import android.text.StaticLayout; import android.text.TextPaint; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.GestureDetector; import android.view.Gravity; import android.view.MotionEvent; import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout; import android.widget.TextView; public class SimpleRatingBar extends TextView { private static final String LOG_TAG = "SimpleRatingBar"; public interface RatingItem { String getName(); boolean isSpam(); /** * will only be called if the item is not marked as spam or as cleared * * @return e.g. 100 for 100% */ int getRatingInPercent(); boolean isCleared(); void onClearClick(); void onSpamClick(); void onRatingSend(int rating); boolean save(); } public static RatingItem newDefaultRatingItem(final String name) { return new RatingItem() { boolean isCleared = true; boolean isSpam = false; private int rating = (int) (Math.random() * 100); @Override public String getName() { return name; } @Override public boolean isSpam() { return isSpam; } @Override public int getRatingInPercent() { return rating; } @Override public boolean isCleared() { return isCleared; } @Override public void onClearClick() { isSpam = false; isCleared = true; } @Override public void onSpamClick() { isSpam = true; isCleared = false; } @Override public void onRatingSend(int rating) { this.rating = rating; isSpam = false; isCleared = false; } @Override public boolean save() { return true; } }; } private static final int DEFAULT_HEIGTH_PER_LINE_IN_DIP = 60; private static final int DEFAULT_PADDING = 10; private static final int TEXT_SIZE_DEFAULT_IN_DIP = 22; private static final float STEP_SIZE_FOR_TEXT_SIZE_STEPS = 2.5f; private static final int SHADOW_LAYER_SIZE = 1; private static final float LINE_THICKNES = 3; private static final int bonusButtonWidth = 8; private static final int ICON_ALPHA = 130; private static final int ICON_MARGIN = 30; private static final int borderColor = ColorCollections.l2pBlueDark; // private static final int spamBoxCheckedColor = // ColorCollections.l2pGrayLight; private static final int spamBoxCheckedColor = ColorCollections.l2pOrange; private static final int badColor = ColorCollections.l2pGray; private static final int goodColor = ColorCollections.l2pGrayLight; private static final int clearedStartColor = ColorCollections.l2pBlue; private static final int clearedEndColor = ColorCollections.l2pBlueDark; private static final int spamBoxNotCheckedColor = badColor; private Bitmap clearIcon; private Bitmap spamIcon; private Bitmap badIcon; private Bitmap goodIcon; int xWidth; int x1Size; int xLeftStartPos; int yTopStartPos; int yHeight; int y1Size; private List<RatingItem> items; private List<Bitmap> itemRatingBars; private Paint iconPaint; private Paint linePaint; private Paint boxBorderPaint; private Paint clearBoxPaint; private Paint spamBoxCheckedPaint; private Paint spamBoxNotCheckedPaint; private Paint ratingPaint; private TextPaint textPaint; // @Deprecated // private Paint backgroundPaint; private int clearIconId; private int spamIconId; private int badIconId; private int goodIconId; public SimpleRatingBar(Context context, int clear, int spam, int bad, int good, ArrayList<RatingItem> attributeNames) { super(context); clearIconId = clear; spamIconId = spam; badIconId = bad; goodIconId = good; init(context, attributeNames); } public SimpleRatingBar(Context context, AttributeSet attrs) { super(context, attrs); init(context, null); } public SimpleRatingBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, null); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { initSimpleRatingBarSpecificViewParamsForTheTextView(); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } private int dipToPixels(int dipValue) { Resources r = getResources(); int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, r.getDisplayMetrics()); return px; } private void initSimpleRatingBarSpecificViewParamsForTheTextView() { int completeHeigth = DEFAULT_HEIGTH_PER_LINE_IN_DIP * items.size(); LayoutParams p = new LinearLayout.LayoutParams( LayoutParams.FILL_PARENT, dipToPixels(completeHeigth)); setLayoutParams(p); setGravity(Gravity.CENTER_HORIZONTAL); setShadowLayer(SHADOW_LAYER_SIZE, 1, 1, Color.BLACK); setPadding(DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING); } private void init(Context context, ArrayList<RatingItem> attributeNames) { initBitmaps(context); if (isInEditMode() || attributeNames == null) { items = loadExampleNames(); } else { items = attributeNames; } initPaints(); } private void initBitmaps(Context context) { if (isInEditMode() || clearIconId == 0 || spamIconId == 0 || badIconId == 0 || goodIconId == 0) { Bitmap b = ImageTransform.createDummyBitmap(); clearIcon = b; spamIcon = b; badIcon = b; goodIcon = b; } else { clearIcon = loadAndProcessImage(context, clearIconId); spamIcon = loadAndProcessImage(context, spamIconId); badIcon = loadAndProcessImage(context, badIconId); goodIcon = loadAndProcessImage(context, goodIconId); } } private Bitmap loadAndProcessImage(Context context, int id) { Bitmap b = IO.loadBitmapFromId(context, id); { Bitmap oldReference = b; b = ImageTransform.makeSquare(b); if (b != oldReference) if (!isInEditMode()) oldReference.recycle(); } // { // Bitmap oldReference = b; // b = ImageTransform.addMargin(b, ICON_MARGIN); // if (b != oldReference) // if (!isInEditMode()) // oldReference.recycle(); // } return b; } private void initPaints() { iconPaint = new Paint(); iconPaint.setAlpha(ICON_ALPHA); iconPaint.setAntiAlias(true); // backgroundPaint = new Paint(); // backgroundPaint.setAlpha(255); linePaint = new Paint(); boxBorderPaint = new Paint(); boxBorderPaint.setColor(borderColor); boxBorderPaint.setStyle(Style.STROKE); boxBorderPaint.setStrokeWidth(LINE_THICKNES); boxBorderPaint.setAntiAlias(true); clearBoxPaint = new Paint(); spamBoxCheckedPaint = new Paint(); spamBoxCheckedPaint.setColor(spamBoxCheckedColor); spamBoxNotCheckedPaint = new Paint(); spamBoxNotCheckedPaint.setColor(spamBoxNotCheckedColor); textPaint = new TextPaint(); textPaint.setColor(getCurrentTextColor()); textPaint.setShadowLayer(SHADOW_LAYER_SIZE, 1, 1, Color.BLACK); textPaint.setTextAlign(Align.CENTER); textPaint.setAntiAlias(true); ratingPaint = new Paint(); ratingPaint.setAntiAlias(true); } private void updateGradients() { ratingPaint.setShader(new LinearGradient(2 * x1Size, 0, xWidth, y1Size, badColor, goodColor, Shader.TileMode.CLAMP)); clearBoxPaint.setShader(new LinearGradient(0, 0, xWidth, y1Size, clearedStartColor, clearedEndColor, Shader.TileMode.CLAMP)); } private ArrayList<RatingItem> loadExampleNames() { NameGenerator g = new NameGenerator(); ArrayList<RatingItem> n = new ArrayList<RatingItem>(); for (int i = 0; i < 10; i++) { String name = g.getName(); for (int j = 0; j < Math.random() * 5; j++) { name += " " + g.getName(); } n.add(newDefaultRatingItem(name)); } return n; } @Override protected void onDraw(Canvas canvas) { // super.onDraw(canvas); if (updateWidthAndHeigth(getWidth(), getHeight())) { updateFieldsAndIcons(); updateBars(); } // canvas.drawRect(xLeftStartPos, yTopStartPos, getWidth() // - getPaddingRight(), getHeight() - getPaddingBottom(), // backgroundPaint); int currentYPos = yTopStartPos; for (int i = 0; i < itemRatingBars.size(); i++) { canvas.drawBitmap(itemRatingBars.get(i), xLeftStartPos, currentYPos, linePaint); currentYPos += y1Size; } } private boolean updateWidthAndHeigth(int width, int height) { width = width - getPaddingLeft() - getPaddingRight(); height = height - getPaddingTop() - getPaddingBottom(); xLeftStartPos = getPaddingLeft(); yTopStartPos = getPaddingTop(); boolean result = false; if (xWidth != width) { xWidth = width; result = true; } if (yHeight != height) { yHeight = height; result = true; } return result; } /** * Call this to update the UI */ private void refreshCompleteUI() { updateWidthAndHeigth(getWidth(), getHeight()); // dont call updateFieldsAndIcons(); updateBars(); postInvalidate(); } private void updateBars() { if (itemRatingBars == null) itemRatingBars = new ArrayList<Bitmap>(); else itemRatingBars.clear(); for (int i = 0; i < items.size(); i++) { itemRatingBars.add(createLineBitmap(items.get(i))); } } private void updateFieldsAndIcons() { y1Size = yHeight / items.size(); x1Size = y1Size + bonusButtonWidth; updateGradients(); Bitmap oldReference = spamIcon; spamIcon = resizeImageAndAddMargin(spamIcon); if (!isInEditMode()) oldReference.recycle(); oldReference = clearIcon; clearIcon = resizeImageAndAddMargin(clearIcon); if (!isInEditMode()) oldReference.recycle(); oldReference = badIcon; badIcon = resizeImageAndAddMargin(badIcon); if (!isInEditMode()) oldReference.recycle(); oldReference = goodIcon; goodIcon = resizeImageAndAddMargin(goodIcon); if (!isInEditMode()) oldReference.recycle(); } private Bitmap resizeImageAndAddMargin(Bitmap b) { Bitmap oldReference = b; b = ImageTransform.resizeBitmap(b, y1Size, y1Size); if (!isInEditMode()) oldReference.recycle(); return b; } private Bitmap createLineBitmap(RatingItem item) { Log.d(LOG_TAG, "new bitmapt for " + item.getName()); int xPos1 = 0; int xPos2 = x1Size; int xPos3 = x1Size * 2; int xPos4 = xWidth - x1Size; int yPos = 0; Bitmap lineBitmap = Bitmap.createBitmap(xWidth, yHeight, Bitmap.Config.ARGB_4444); Canvas canvas = new Canvas(lineBitmap); if (item.isCleared()) { canvas.drawRect(xPos1, 0, xWidth, y1Size, clearBoxPaint); } else if (item.isSpam()) { canvas.drawRect(xPos2, 0, xPos3, y1Size, spamBoxCheckedPaint); } else { canvas.drawRect(xPos2, 0, xPos3, y1Size, spamBoxNotCheckedPaint); drawRatingBar(item, xPos3, canvas); } canvas.drawRect(xPos1, 0, xPos2, y1Size, clearBoxPaint); canvas.drawBitmap(clearIcon, xPos1 + bonusButtonWidth / 2, yPos, iconPaint); canvas.drawRect(xPos1, 0, xPos2, y1Size, boxBorderPaint); canvas.drawBitmap(spamIcon, xPos2 + bonusButtonWidth / 2, yPos, iconPaint); canvas.drawRect(xPos2, 0, xPos3 - 1, y1Size, boxBorderPaint); canvas.drawBitmap(badIcon, xPos3 + bonusButtonWidth, yPos, iconPaint); canvas.drawBitmap(goodIcon, xPos4, yPos, iconPaint); drawItemText(item, xPos3, canvas); canvas.drawRect(xPos3, 0, xWidth - 1, y1Size, boxBorderPaint); return lineBitmap; } private void drawItemText(RatingItem item, int xTextStartPos, Canvas canvas) { String text = item.getName(); if (isInEditMode()) { int textCenterX = (xWidth + 2 * x1Size) / 2; int textCenterY = 0; textCenterY = y1Size - 10; textPaint.setTextSize(dipToPixels(TEXT_SIZE_DEFAULT_IN_DIP)); canvas.drawText(text, textCenterX, textCenterY, textPaint); } else { int yStart = 0; int textAreaWidth = xWidth - 2 * x1Size; int textAreaHeigth = y1Size; drawText(canvas, xTextStartPos, yStart, textAreaWidth, textAreaHeigth, text, textPaint, dipToPixels(TEXT_SIZE_DEFAULT_IN_DIP), STEP_SIZE_FOR_TEXT_SIZE_STEPS); } } private static void drawText(Canvas canvas, int xStart, int yStart, int xWidth, int yHeigth, String textToDisplay, TextPaint paintToUse, float startTextSizeInPixels, float stepSizeForTextSizeSteps) { // Text view line spacing multiplier float mSpacingMult = 1.0f; // Text view additional line spacing float mSpacingAdd = 0.0f; StaticLayout l = null; do { paintToUse.setTextSize(startTextSizeInPixels); startTextSizeInPixels -= stepSizeForTextSizeSteps; l = new StaticLayout(textToDisplay, paintToUse, xWidth, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, true); } while (l.getHeight() > yHeigth); int textCenterX = xStart + (xWidth / 2); int textCenterY = (yHeigth - l.getHeight()) / 2; canvas.save(); canvas.translate(textCenterX, textCenterY); l.draw(canvas); canvas.restore(); } private void drawRatingBar(RatingItem item, int xPos3, Canvas canvas) { float rating = item.getRatingInPercent(); int ratingBarLength = (int) (rating / 100f * (xWidth - 2 * x1Size)); canvas.drawRect(xPos3, 0, xPos3 + ratingBarLength, y1Size, ratingPaint); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getX() >= 2 * x1Size) { // tryToSwitchOfParentScrollView(); getParent().requestDisallowInterceptTouchEvent(true); sendRatingEvent(event.getX(), event.getY()); return true; } else { getParent().requestDisallowInterceptTouchEvent(false); return buttonGestureDetector.onTouchEvent(event); } } private void sendRatingEvent(float x, float y) { int nr = (int) (y / y1Size); if (nr >= 0 && nr < items.size()) { RatingItem i = items.get(nr); int rating = (int) (100 * (x - 2 * x1Size) / (xWidth - 2 * x1Size)); if (rating > 100) rating = 100; if (i.getRatingInPercent() != rating) { i.onRatingSend(rating); updateBitmatForItemNr(nr, i); } } } private GestureDetector buttonGestureDetector = new GestureDetector( new GestureDetector.SimpleOnGestureListener() { public boolean onDown(MotionEvent e) { return true; }; public boolean onSingleTapUp(MotionEvent e) { sendClichEvent(e.getX(), e.getY()); return true; } }); private void sendClichEvent(float x, float y) { int nr = (int) (y / y1Size); if (nr >= 0 && nr < items.size()) { if (x < x1Size) { // Clear click RatingItem i = items.get(nr); i.onClearClick(); updateBitmatForItemNr(nr, i); } else if (x < 2 * x1Size) { // spam click RatingItem i = items.get(nr); i.onSpamClick(); updateBitmatForItemNr(nr, i); } } } private void updateBitmatForItemNr(int nr, RatingItem i) { itemRatingBars.set(nr, createLineBitmap(i)); postInvalidate(); } }