I saw this library :
https://github.com/bluejamesbond/TextJustify-Android
but it's so complicated and don't know how to use it. I have a TextView that fill it programmatically from database in java. how can I use a simple library to justify it?!
UPDATE
I found this class in Github and it's perfect but I don't remember the link...!
public class JustifiedTextView extends View {
private Context mContext;
private XmlToClassAttribHandler mXmlParser;
private TextPaint textPaint;
private int lineSpace = 0;
private int lineHeight;
private int textAreaWidth;
private int measuredViewHeight, measuredViewWidth;
private String text;
private List<String> lineList = new ArrayList<String>();
/**
* when we want to draw text after view created to avoid loop in drawing we use this boolean
*/
boolean hasTextBeenDrown = false;
public JustifiedTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
constructor(context, attrs);
}
public JustifiedTextView(Context context, AttributeSet attrs) {
super(context, attrs);
constructor(context, attrs);
}
public JustifiedTextView(Context context) {
super(context);
constructor(context, null);
}
private void constructor(Context context, AttributeSet attrs) {
mContext = context;
mXmlParser = new XmlToClassAttribHandler(mContext, attrs);
initTextPaint();
if (attrs != null) {
String text;
int textColor;
int textSize;
int textSizeUnit;
text = mXmlParser.getTextValue();
textColor = mXmlParser.getColorValue();
textSize = mXmlParser.getTextSize();
textSizeUnit = mXmlParser.gettextSizeUnit();
setText(text);
setTextColor(textColor);
if (textSizeUnit == -1)
setTextSize(textSize);
else
setTextSize(textSizeUnit, textSize);
}
ViewTreeObserver observer = getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (hasTextBeenDrown)
return;
hasTextBeenDrown = true;
setTextAreaWidth(getWidth() - (getPaddingLeft() + getPaddingRight()));
calculate();
}
});
}
private void calculate() {
setLineHeight(getTextPaint());
lineList.clear();
lineList = divideOriginalTextToStringLineList(getText());
setMeasuredDimentions(lineList.size(), getLineHeight(), getLineSpace());
measure(getMeasuredViewWidth(), getMeasuredViewHeight());
}
private void initTextPaint() {
textPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
textPaint.setTextAlign( Paint.Align.RIGHT);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getMeasuredViewWidth() > 0) {
requestLayout();
setMeasuredDimension(getMeasuredViewWidth(), getMeasuredViewHeight());
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
invalidate();
}
private int rowIndex = 0, colIndex = 0;
#Override
protected void onDraw(Canvas canvas) {
rowIndex = getPaddingTop();
if (getAlignment() == Paint.Align.RIGHT)
colIndex = getPaddingLeft() + getTextAreaWidth();
else
colIndex = getPaddingLeft();
for (int i = 0; i < lineList.size(); i++) {
rowIndex += getLineHeight() + getLineSpace();
canvas.drawText(lineList.get(i), colIndex, rowIndex, getTextPaint());
}
}
/**
* this method get the string and divide it to a list of StringLines according to textAreaWidth
*
* #param originalText
* #return
*/
private List<String> divideOriginalTextToStringLineList(String originalText) {
List<String> listStringLine = new ArrayList<String>();
String line = "";
float textWidth;
String[] listParageraphes = originalText.split("\n");
for (int j = 0; j < listParageraphes.length; j++) {
String[] arrayWords = listParageraphes[j].split(" ");
for (int i = 0; i < arrayWords.length; i++) {
line += arrayWords[i] + " ";
textWidth = getTextPaint().measureText(line);
//if text width is equal to textAreaWidth then just add it to ListStringLine
if (getTextAreaWidth() == textWidth) {
listStringLine.add(line);
line = "";//make line clear
continue;
}
//else if text width excite textAreaWidth then remove last word and justify the StringLine
else if (getTextAreaWidth() < textWidth) {
int lastWordCount = arrayWords[i].length();
//remove last word that cause line width to excite textAreaWidth
line = line.substring(0, line.length() - lastWordCount - 1);
// if line is empty then should be skipped
if (line.trim().length() == 0)
continue;
//and then we need to justify line
line = justifyTextLine(textPaint, line.trim(), getTextAreaWidth());
listStringLine.add(line);
line = "";
i--;
continue;
}
//if we are now at last line of paragraph then just add it
if (i == arrayWords.length - 1) {
listStringLine.add(line);
line = "";
}
}
}
return listStringLine;
}
/**
* this method add space in line until line width become equal to textAreaWidth
*
* #param lineString
* #param lineWidth
* #param textAreaWidth
* #return
*/
private String justifyTextLine(TextPaint textPaint, String lineString, int textAreaWidth) {
int gapIndex = 0;
float lineWidth = textPaint.measureText(lineString);
while (lineWidth < textAreaWidth && lineWidth > 0) {
gapIndex = lineString.indexOf(" ", gapIndex + 2);
if (gapIndex == -1) {
gapIndex = 0;
gapIndex = lineString.indexOf(" ", gapIndex + 1);
if (gapIndex == -1)
return lineString;
}
lineString = lineString.substring(0, gapIndex) + " " + lineString.substring(gapIndex + 1, lineString.length());
lineWidth = textPaint.measureText(lineString);
}
return lineString;
}
/**
* this method calculate height for a line of text according to defined TextPaint
*
* #param textPaint
*/
private void setLineHeight(TextPaint textPaint) {
Rect bounds = new Rect();
String sampleStr = "این حسین کیست که عالم همه دیوانه اوست";
textPaint.getTextBounds(sampleStr, 0, sampleStr.length(), bounds);
setLineHeight(bounds.height());
}
/**
* this method calculate view's height according to line count and line height and view's width
*
* #param lineListSize
* #param lineHeigth
* #param lineSpace
*/
public void setMeasuredDimentions(int lineListSize, int lineHeigth, int lineSpace) {
int mHeight = lineListSize * (lineHeigth + lineSpace) + lineSpace;
mHeight += getPaddingRight() + getPaddingLeft();
setMeasuredViewHeight(mHeight);
setMeasuredViewWidth(getWidth());
}
private int getTextAreaWidth() {
return textAreaWidth;
}
private void setTextAreaWidth(int textAreaWidth) {
this.textAreaWidth = textAreaWidth;
}
private int getLineHeight() {
return lineHeight;
}
private int getMeasuredViewHeight() {
return measuredViewHeight;
}
private void setMeasuredViewHeight(int measuredViewHeight) {
this.measuredViewHeight = measuredViewHeight;
}
private int getMeasuredViewWidth() {
return measuredViewWidth;
}
private void setMeasuredViewWidth(int measuredViewWidth) {
this.measuredViewWidth = measuredViewWidth;
}
private void setLineHeight(int lineHeight) {
this.lineHeight = lineHeight;
}
public String getText() {
return text;
}
/**
* Sets the string value of the JustifiedTextView. JustifiedTextView does not accept HTML-like formatting.
* Related XML Attributes
* -noghteh:text
*
* #param text
*/
public void setText(String text) {
this.text = text;
calculate();
invalidate();
}
public void setText(int resid) {
setText(mContext.getResources().getString(resid));
}
public Typeface getTypeFace() {
return getTextPaint().getTypeface();
}
public void setTypeFace(Typeface typeFace) {
getTextPaint().setTypeface(typeFace);
}
public float getTextSize() {
return getTextPaint().getTextSize();
}
public void setTextSize(int unit, float textSize) {
textSize = TypedValue.applyDimension(unit, textSize, mContext.getResources().getDisplayMetrics());
setTextSize(textSize);
}
private void setTextSize(float textSize) {
getTextPaint().setTextSize(textSize);
calculate();
invalidate();
}
public TextPaint getTextPaint() {
return textPaint;
}
public void setTextPaint(TextPaint textPaint) {
this.textPaint = textPaint;
}
/**
* set text color
*
* #param textColor
*/
public void setTextColor(int textColor) {
getTextPaint().setColor(textColor);
invalidate();
}
/**
* define space between lines
*
* #param lineSpace
*/
public void setLineSpacing(int lineSpace) {
this.lineSpace = lineSpace;
invalidate();
}
/**
* #return text color
*/
public int getTextColor() {
return getTextPaint().getColor();
}
/**
* space between lines - default is 0
*
* #return
*/
public int getLineSpace() {
return lineSpace;
}
/**
* get text alignment
*
* #return
*/
public Paint.Align getAlignment() {
return getTextPaint().getTextAlign();
}
/**
* Align text according to your language
*
* #param align
*/
public void setAlignment(Paint.Align align) {
getTextPaint().setTextAlign(align);
invalidate();
}}
And this class :
public class XmlToClassAttribHandler {
private Resources mRes;
private Context mContext;
private AttributeSet mAttributeSet;
private String namespace="http://noghteh.ir";
private final String KEY_TEXT="text";
private final String KEY_TEXT_SIZE="textSize";
private final String KEY_TEXT_COLOR="textColor";
public XmlToClassAttribHandler(Context context,AttributeSet attributeSet){
mContext=context;
mRes=mContext.getResources();
mAttributeSet=attributeSet;
}
public String getTextValue(){
String value=mAttributeSet.getAttributeValue(namespace, KEY_TEXT);
if (value==null)
return "";
if (value.length()>1 &&
value.charAt(0)=='#' &&
value.contains("#string/")){
int resId=mRes.getIdentifier(mContext.getPackageName()+":"+value.substring(1), null,null);
value=mRes.getString(resId);
}
return value;
}
public int getColorValue(){
String value=mAttributeSet.getAttributeValue(namespace, KEY_TEXT_COLOR);
int color= Color.BLACK;
if (value==null)
return color;
if (value.length()>1 &&
value.charAt(0)=='#' &&
value.contains("#color/")){
int resId=mRes.getIdentifier(mContext.getPackageName()+":"+value.substring(1), null,null);
color=mRes.getColor(resId);
return color;
}
try{
color=Color.parseColor(value);
}
catch(Exception e){
return Color.BLACK;
}
return color;
}
public int getTextSize() {
int textSize=12;
String value=mAttributeSet.getAttributeValue(namespace, KEY_TEXT_SIZE );
if (value==null)
return textSize;
if (value.length()>1 &&
value.charAt(0)=='#' &&
value.contains("#dimen/")){
int resId=mRes.getIdentifier(mContext.getPackageName()+":"+value.substring(1), null,null);
textSize=mRes.getDimensionPixelSize(resId);
return textSize;
}
try{
textSize=Integer.parseInt(value.substring(0, value.length()-2));
}
catch(Exception e){
return 12;
}
return textSize;
}
public int gettextSizeUnit() {
String value=mAttributeSet.getAttributeValue(namespace, KEY_TEXT_SIZE );
if (value==null)
return TypedValue.COMPLEX_UNIT_SP;
try{
String type=value.substring(value.length()-2, value.length());
if (type.equals("dp"))
return TypedValue.COMPLEX_UNIT_DIP;
else if (type.equals("sp"))
return TypedValue.COMPLEX_UNIT_SP;
else if (type.equals("pt"))
return TypedValue.COMPLEX_UNIT_PT;
else if (type.equals("mm"))
return TypedValue.COMPLEX_UNIT_MM;
else if (type.equals("in"))
return TypedValue.COMPLEX_UNIT_IN;
else if (type.equals("px"))
return TypedValue.COMPLEX_UNIT_PX;
}
catch(Exception e){
return -1;
}
return -1;
}}
and then define a JustifiedTextView instead of simple TextView in your XML file...!!
Follow the instructions in the readme.
Add to your build.gradle
dependencies {
compile 'com.github.bluejamesbond:textjustify-android:2.1.1'
}
Then you define a DocumentView instead of a TextView:
<com.bluejamesbond.text.DocumentView
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
You could also use https://github.com/merterhk/JustifiedTextView which is just a single class to avoid having to incorporate a new library.
Related
I am using custom calendar where everything works fine.
For eg: If today's date is 8th February.
In February, it shows 8th as different color which is today's date and others are in black color.
But when swipped to previous month January, date 8 alone is showing. How to remove the today's date in previous month?
Here is screenshot
When i click to previous month,you can see 8 alone which is current today's date is showing in previous month.
Here is code:
public class CalendarNumbersView extends View {
public static final int MAX_WEEKS_IN_MONTH = 7;
private float MAX_SELECTION_FINGER_SHIFT_DIST = 5.0f;
private TextPaint paint;
private int cellPadding;
private int textColor;
private int inactiveTextColor;
private int selectionTextColor;
private int cellBackgroundColor;
private int cellSelectionBackgroundColor;
private int dayNamesTextColor;
private int dayNamesBackgroundColor;
private boolean showDayNames = true;
private Locale locale = Locale.getDefault();
private Calendar selectedDate;
private Calendar shownMonth;
private DateSelectionListener listener = null;
//temporary and cache values
private int _cachedCellSideWidth = 0;
private int _cachedCellSideHeight = 0;
private Calendar _calendar = Calendar.getInstance();
private Rect _rect = new Rect();
private float _textHeight = 0;
private float _x;
private float _y;
private Typeface _boldTypeface;
private Typeface _defaultTypeface;
public interface DateSelectionListener {
void onDateSelected(Calendar selectedDate);
}
public static class CalendarDayCellCoord {
public int col;
public int row;
public CalendarDayCellCoord(int col, int row) {
this.col = col;
this.row = row;
}
}
public CalendarNumbersView(Context context) {
super(context);
init(null);
}
public CalendarNumbersView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public CalendarNumbersView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {
paint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
paint.setTextSize(getResources().getDimensionPixelSize(R.dimen.calendar_default_text_size));
textColor = getResources().getColor(R.color.calendar_default_text_color);
//changed by adding color in inactive text.(previous month days)
inactiveTextColor = Color.parseColor("#FFFFFFFF");
selectionTextColor = getResources().getColor(R.color.calendar_default_selection_text_color);
cellPadding = getResources().getDimensionPixelSize(R.dimen.calendar_default_cell_padding);
cellBackgroundColor = getResources().getColor(R.color.calendar_default_cell_background_color);
//cellSelectionBackgroundColor = getResources().getColor(R.color.calendar_default_cell_selection_background_color);
dayNamesTextColor = getResources().getColor(R.color.calendar_default_day_names_cell_text_color);
dayNamesBackgroundColor = getResources().getColor(R.color.calendar_default_day_names_cell_background_color);
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.CalendarNumbersView);
if (ta != null) {
paint.setTextSize(ta.getDimensionPixelSize(R.styleable.CalendarNumbersView_fontSize, (int) paint.getTextSize()));
textColor = ta.getColor(R.styleable.CalendarNumbersView_textColor, textColor);
inactiveTextColor = ta.getColor(R.styleable.CalendarNumbersView_inactiveTextColor, inactiveTextColor);
selectionTextColor = ta.getColor(R.styleable.CalendarNumbersView_selectionTextColor, selectionTextColor);
cellPadding = ta.getDimensionPixelSize(R.styleable.CalendarNumbersView_cellPadding, cellPadding);
cellBackgroundColor = ta.getColor(R.styleable.CalendarNumbersView_cellBackgroundColor, cellBackgroundColor);
cellSelectionBackgroundColor = ta.getColor(R.styleable.CalendarNumbersView_cellSelectionBackgroundColor, cellSelectionBackgroundColor);
dayNamesTextColor = ta.getColor(R.styleable.CalendarNumbersView_cellDayNamesCellTextColor, dayNamesTextColor);
dayNamesBackgroundColor = ta.getColor(R.styleable.CalendarNumbersView_cellDayNamesCellBackgroundColor, dayNamesBackgroundColor);
}
selectedDate = Calendar.getInstance();
shownMonth = (Calendar) selectedDate.clone();
}
public int calculateQuadCellSideWidth() {
Rect bounds = new Rect();
String str = "WW";//widest possible cell string
paint.getTextBounds(str, 0, str.length(), bounds);
int maxWidth = bounds.width();
int maxHeight = bounds.height();
_textHeight = bounds.height();
return Math.max(maxWidth, maxHeight) + cellPadding * 2;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int quadCellSideWidth = calculateQuadCellSideWidth();
int calculatedWidth = quadCellSideWidth * shownMonth.getActualMaximum(Calendar.DAY_OF_WEEK) + getPaddingLeft() + getPaddingRight();
int calculatedHeight = quadCellSideWidth * MAX_WEEKS_IN_MONTH + getPaddingTop() + getPaddingBottom();
if (showDayNames) {
calculatedHeight += quadCellSideWidth;
}
int minimumWidth = Math.max(getSuggestedMinimumWidth(), calculatedWidth);
int minimumHeight = Math.max(getSuggestedMinimumHeight(), calculatedHeight);
int width = chooseSize(minimumWidth, widthMeasureSpec);
int height = chooseSize(minimumHeight, heightMeasureSpec);
setMeasuredDimension(width, height);
}
public int chooseSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
case MeasureSpec.AT_MOST:
result = size;
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
_cachedCellSideWidth = (w - getPaddingRight() - getPaddingLeft()) / shownMonth.getActualMaximum(Calendar.DAY_OF_WEEK);
_cachedCellSideHeight = (h - getPaddingTop() - getPaddingBottom()) / MAX_WEEKS_IN_MONTH;
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (showDayNames) {
setCalendarToFirstVisibleDay(_calendar);
DateFormatSymbols symbols = new DateFormatSymbols(locale);
for (int col = 0; col < _calendar.getActualMaximum(Calendar.DAY_OF_WEEK); col++) {
String str = _calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, locale);
String name = str.substring(0, str.length() - 1);
drawCell(canvas, -1, col, dayNamesTextColor, dayNamesBackgroundColor, name, true);
_calendar.add(Calendar.DAY_OF_MONTH, 1);
}
}
setCalendarToFirstVisibleDay(_calendar);
for (int row = 0; row < MAX_WEEKS_IN_MONTH; row++) {
for (int col = 0; col < _calendar.getActualMaximum(Calendar.DAY_OF_WEEK); col++) {
int textColor;
int backgroundColor;
if (_calendar.get(Calendar.DAY_OF_YEAR) == selectedDate.get(Calendar.DAY_OF_YEAR) &&
_calendar.get(Calendar.YEAR) == selectedDate.get(Calendar.YEAR)) {
//here is the logic applied. If both are same, apply color. But why it's affecting in previous calendar.
textColor = selectionTextColor;
backgroundColor = cellSelectionBackgroundColor;
} else {
if (_calendar.get(Calendar.MONTH) == shownMonth.get(Calendar.MONTH)) {
textColor = this.textColor;
} else {
textColor = inactiveTextColor;
}
backgroundColor = cellBackgroundColor;
}
int day = _calendar.get(Calendar.DAY_OF_MONTH);
String str = Integer.toString(day);
drawCell(canvas, row, col, textColor, backgroundColor, str, false);
_calendar.add(Calendar.DAY_OF_MONTH, 1);
}
}
}
private void drawCell(Canvas canvas, int row, int col, int textColor, int backgroundColor, String str, boolean bold) {
getRectForCell(col, row, _rect);
paint.setColor(backgroundColor);
_rect.inset(cellPadding, cellPadding);
canvas.drawRect(_rect, paint);
_rect.inset(-cellPadding, -cellPadding);
paint.setColor(textColor);
if (bold) {
if (_boldTypeface == null) {
_boldTypeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);//su,mo,tu,wed
}
paint.setTypeface(_boldTypeface);
} else {
if (_defaultTypeface == null) {
_defaultTypeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);
}
paint.setTypeface(_defaultTypeface);
}
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(str,
_rect.left + _cachedCellSideWidth / 2f,
_rect.top + _cachedCellSideHeight / 2f + _textHeight / 2f - paint.getFontMetrics().descent / 2,
paint);
}
private void setCalendarToFirstVisibleDay(Calendar calendar) {
calendar.setTime(shownMonth.getTime());
calendar.set(Calendar.DAY_OF_MONTH, 1);
int firstDayInWeek = calendar.getFirstDayOfWeek();
int firstDayOfWeekOfCurrentMonth = calendar.get(Calendar.DAY_OF_WEEK);
int shift;
if (firstDayInWeek > firstDayOfWeekOfCurrentMonth) {
shift = -(firstDayOfWeekOfCurrentMonth + calendar.getActualMaximum(Calendar.DAY_OF_WEEK) - firstDayInWeek);
} else {
shift = -(firstDayOfWeekOfCurrentMonth - firstDayInWeek);
}
calendar.add(Calendar.DAY_OF_MONTH, shift);
}
private void getRectForCell(int col, int row, Rect outRect) {
if (showDayNames) {
row++;
}
outRect.set(getPaddingLeft() + col * _cachedCellSideWidth,
getPaddingTop() + row * _cachedCellSideHeight,
getPaddingLeft() + col * _cachedCellSideWidth + _cachedCellSideWidth,
getPaddingTop() + row * _cachedCellSideHeight + _cachedCellSideHeight);
}
private CalendarDayCellCoord getCellForCoords(float x, float y) {
if (x < getPaddingLeft() ||
x >= getWidth() - getPaddingRight() ||
y < getPaddingTop() ||
y >= getHeight() - getPaddingBottom()) {
return null;
}
CalendarDayCellCoord coord = new CalendarDayCellCoord(
(int) (x - getPaddingLeft()) / _cachedCellSideWidth,
(int) (y - getPaddingTop()) / _cachedCellSideHeight
);
if (showDayNames) {
coord.row--;
if (coord.row < 0) {
return null;
}
}
return coord;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
_x = event.getX();
_y = event.getY();
return true;
case MotionEvent.ACTION_UP:
float x = event.getX();
float y = event.getY();
if (Math.sqrt(Math.pow(x - _x, 2) + Math.pow(y - _y, 2)) <= MAX_SELECTION_FINGER_SHIFT_DIST) {
selectDayAt(x, y);
}
return true;
default:
return super.onTouchEvent(event);
}
}
private void selectDayAt(float x, float y) {
CalendarDayCellCoord cellCoords = getCellForCoords(x, y);
if (cellCoords == null) {
return;
}
setCalendarToFirstVisibleDay(_calendar);
_calendar.add(Calendar.DAY_OF_YEAR, cellCoords.col);
_calendar.add(Calendar.WEEK_OF_MONTH, cellCoords.row);
selectedDate.setTime(_calendar.getTime());
if (listener != null) {
listener.onDateSelected(selectedDate);
}
invalidate();
}
public int getCellBackgroundColor() {
return cellBackgroundColor;
}
public void setCellBackgroundColor(int cellBackgroundColor) {
this.cellBackgroundColor = cellBackgroundColor;
invalidate();
}
public int getCellPadding() {
return cellPadding;
}
public void setCellPadding(int cellPadding) {
this.cellPadding = cellPadding;
invalidate();
}
public int getCellSelectionBackgroundColor() {
return cellSelectionBackgroundColor;
}
public void setCellSelectionBackgroundColor(int cellSelectionBackgroundColor) {
this.cellSelectionBackgroundColor = cellSelectionBackgroundColor;
invalidate();
}
public int getInactiveTextColor() {
return inactiveTextColor;
}
public void setInactiveTextColor(int inactiveTextColor) {
this.inactiveTextColor = inactiveTextColor;
invalidate();
}
public DateSelectionListener getListener() {
return listener;
}
public void setListener(DateSelectionListener listener) {
this.listener = listener;
}
public Calendar getSelectedDate() {
return selectedDate;
}
public void setSelectedDate(Calendar selectedDate) {
this.selectedDate = selectedDate;
invalidate();
}
public int getSelectionTextColor() {
return selectionTextColor;
}
public void setSelectionTextColor(int selectionTextColor) {
this.selectionTextColor = selectionTextColor;
invalidate();
}
public int getTextColor() {
return textColor;
}
public void setTextColor(int textColor) {
this.textColor = textColor;
invalidate();
}
public Calendar getShownMonth() {
return shownMonth;
}
public void setShownMonth(Calendar shownMonth) {
this.shownMonth = shownMonth;
invalidate();
}
public boolean isShowDayNames() {
return showDayNames;
}
public void setShowDayNames(boolean showDayNames) {
this.showDayNames = showDayNames;
invalidate();
}
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
invalidate();
}
public int getDayNamesBackgroundColor() {
return dayNamesBackgroundColor;
}
public void setDayNamesBackgroundColor(int dayNamesBackgroundColor) {
this.dayNamesBackgroundColor = dayNamesBackgroundColor;
invalidate();
}
public int getDayNamesTextColor() {
return dayNamesTextColor;
}
public void setDayNamesTextColor(int dayNamesTextColor) {
this.dayNamesTextColor = dayNamesTextColor;
invalidate();
}
}
If you see the above code,at one particular line, I have applied color only in current month of today's date. But why it's displaying in previous month?
[extracted the above specific code lines..]
if (_calendar.get(Calendar.DAY_OF_YEAR) == selectedDate.get(Calendar.DAY_OF_YEAR) &&
_calendar.get(Calendar.YEAR) == selectedDate.get(Calendar.YEAR)) {
//here is the logic applied. If both are same, apply color. But why it's affecting in previous calendar.
textColor = selectionTextColor;//today's date
backgroundColor = cellSelectionBackgroundColor;
}
Update the condition for check the month also
if (_calendar.get(Calendar.DAY_OF_YEAR) == selectedDate.get(Calendar.DAY_OF_YEAR) &&
_calendar.get(Calendar.YEAR) == selectedDate.get(Calendar.YEAR)
&& _calendar.get(Calendar.MONTH) == shownMonth.get(Calendar.MONTH)) {
textColor = selectionTextColor;
backgroundColor = cellSelectionBackgroundColor;
} else {
if (_calendar.get(Calendar.MONTH) == shownMonth.get(Calendar.MONTH)) {
textColor = this.textColor;
} else {
textColor = inactiveTextColor;
}
backgroundColor = cellBackgroundColor;
}
How can i do this with android (java)?
You can use below Range-Seek-Bar
check below class souce code available here
public class RangeSeekBar<T extends Number> extends ImageView {
public static final Integer DEFAULT_MINIMUM = 0;
public static final Integer DEFAULT_MAXIMUM = 100;
public static final int HEIGHT_IN_DP = 30;
public static final int TEXT_LATERAL_PADDING_IN_DP = 3;
private static final int INITIAL_PADDING_IN_DP = 8;
private final int LINE_HEIGHT_IN_DP = 1;
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Bitmap thumbImage = BitmapFactory.decodeResource(getResources(), R.drawable.seek_thumb_normal);
private final Bitmap thumbPressedImage = BitmapFactory.decodeResource(getResources(),
R.drawable.seek_thumb_pressed);
private final Bitmap thumbDisabledImage = BitmapFactory.decodeResource(getResources(),
R.drawable.seek_thumb_disabled);
private final float thumbWidth = thumbImage.getWidth();
private final float thumbHalfWidth = 0.5f * thumbWidth;
private final float thumbHalfHeight = 0.5f * thumbImage.getHeight();
private float INITIAL_PADDING;
private float padding;
private T absoluteMinValue, absoluteMaxValue;
private NumberType numberType;
private double absoluteMinValuePrim, absoluteMaxValuePrim;
private double normalizedMinValue = 0d;
private double normalizedMaxValue = 1d;
private Thumb pressedThumb = null;
private boolean notifyWhileDragging = false;
private OnRangeSeekBarChangeListener<T> listener;
/**
* Default color of a {#link RangeSeekBar}, #FF33B5E5. This is also known as "Ice Cream Sandwich" blue.
*/
public static final int DEFAULT_COLOR = Color.argb(0xFF, 0x33, 0xB5, 0xE5);
/**
* An invalid pointer id.
*/
public static final int INVALID_POINTER_ID = 255;
// Localized constants from MotionEvent for compatibility
// with API < 8 "Froyo".
public static final int ACTION_POINTER_UP = 0x6, ACTION_POINTER_INDEX_MASK = 0x0000ff00, ACTION_POINTER_INDEX_SHIFT = 8;
private float mDownMotionX;
private int mActivePointerId = INVALID_POINTER_ID;
private int mScaledTouchSlop;
private boolean mIsDragging;
private int mTextOffset;
private int mTextSize;
private int mDistanceToTop;
private RectF mRect;
private static final int DEFAULT_TEXT_SIZE_IN_DP = 14;
private static final int DEFAULT_TEXT_DISTANCE_TO_BUTTON_IN_DP = 8;
private static final int DEFAULT_TEXT_DISTANCE_TO_TOP_IN_DP = 8;
private boolean mSingleThumb;
public RangeSeekBar(Context context) {
super(context);
init(context, null);
}
public RangeSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public RangeSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private T extractNumericValueFromAttributes(TypedArray a, int attribute, int defaultValue) {
TypedValue tv = a.peekValue(attribute);
if (tv == null) {
return (T) Integer.valueOf(defaultValue);
}
int type = tv.type;
if (type == TypedValue.TYPE_FLOAT) {
return (T) Float.valueOf(a.getFloat(attribute, defaultValue));
} else {
return (T) Integer.valueOf(a.getInteger(attribute, defaultValue));
}
}
private void init(Context context, AttributeSet attrs) {
if (attrs == null) {
setRangeToDefaultValues();
} else {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.RangeSeekBar, 0, 0);
setRangeValues(
extractNumericValueFromAttributes(a, R.styleable.RangeSeekBar_absoluteMinValue, DEFAULT_MINIMUM),
extractNumericValueFromAttributes(a, R.styleable.RangeSeekBar_absoluteMaxValue, DEFAULT_MAXIMUM));
mSingleThumb = a.getBoolean(R.styleable.RangeSeekBar_singleThumb, false);
a.recycle();
}
setValuePrimAndNumberType();
INITIAL_PADDING = PixelUtil.dpToPx(context, INITIAL_PADDING_IN_DP);
mTextSize = PixelUtil.dpToPx(context, DEFAULT_TEXT_SIZE_IN_DP);
mDistanceToTop = PixelUtil.dpToPx(context, DEFAULT_TEXT_DISTANCE_TO_TOP_IN_DP);
mTextOffset = this.mTextSize + PixelUtil.dpToPx(context,
DEFAULT_TEXT_DISTANCE_TO_BUTTON_IN_DP) + this.mDistanceToTop;
float lineHeight = PixelUtil.dpToPx(context, LINE_HEIGHT_IN_DP);
mRect = new RectF(padding,
mTextOffset + thumbHalfHeight - lineHeight / 2,
getWidth() - padding,
mTextOffset + thumbHalfHeight + lineHeight / 2);
// make RangeSeekBar focusable. This solves focus handling issues in case EditText widgets are being used along with the RangeSeekBar within ScollViews.
setFocusable(true);
setFocusableInTouchMode(true);
mScaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
public void setRangeValues(T minValue, T maxValue) {
this.absoluteMinValue = minValue;
this.absoluteMaxValue = maxValue;
setValuePrimAndNumberType();
}
#SuppressWarnings("unchecked")
// only used to set default values when initialised from XML without any values specified
private void setRangeToDefaultValues() {
this.absoluteMinValue = (T) DEFAULT_MINIMUM;
this.absoluteMaxValue = (T) DEFAULT_MAXIMUM;
setValuePrimAndNumberType();
}
private void setValuePrimAndNumberType() {
absoluteMinValuePrim = absoluteMinValue.doubleValue();
absoluteMaxValuePrim = absoluteMaxValue.doubleValue();
numberType = NumberType.fromNumber(absoluteMinValue);
}
public void resetSelectedValues() {
setSelectedMinValue(absoluteMinValue);
setSelectedMaxValue(absoluteMaxValue);
}
public boolean isNotifyWhileDragging() {
return notifyWhileDragging;
}
/**
* Should the widget notify the listener callback while the user is still dragging a thumb? Default is false.
*
* #param flag
*/
public void setNotifyWhileDragging(boolean flag) {
this.notifyWhileDragging = flag;
}
/**
* Returns the absolute minimum value of the range that has been set at construction time.
*
* #return The absolute minimum value of the range.
*/
public T getAbsoluteMinValue() {
return absoluteMinValue;
}
/**
* Returns the absolute maximum value of the range that has been set at construction time.
*
* #return The absolute maximum value of the range.
*/
public T getAbsoluteMaxValue() {
return absoluteMaxValue;
}
/**
* Returns the currently selected min value.
*
* #return The currently selected min value.
*/
public T getSelectedMinValue() {
return normalizedToValue(normalizedMinValue);
}
/**
* Sets the currently selected minimum value. The widget will be invalidated and redrawn.
*
* #param value The Number value to set the minimum value to. Will be clamped to given absolute minimum/maximum range.
*/
public void setSelectedMinValue(T value) {
// in case absoluteMinValue == absoluteMaxValue, avoid division by zero when normalizing.
if (0 == (absoluteMaxValuePrim - absoluteMinValuePrim)) {
setNormalizedMinValue(0d);
} else {
setNormalizedMinValue(valueToNormalized(value));
}
}
/**
* Returns the currently selected max value.
*
* #return The currently selected max value.
*/
public T getSelectedMaxValue() {
return normalizedToValue(normalizedMaxValue);
}
/**
* Sets the currently selected maximum value. The widget will be invalidated and redrawn.
*
* #param value The Number value to set the maximum value to. Will be clamped to given absolute minimum/maximum range.
*/
public void setSelectedMaxValue(T value) {
// in case absoluteMinValue == absoluteMaxValue, avoid division by zero when normalizing.
if (0 == (absoluteMaxValuePrim - absoluteMinValuePrim)) {
setNormalizedMaxValue(1d);
} else {
setNormalizedMaxValue(valueToNormalized(value));
}
}
/**
* Registers given listener callback to notify about changed selected values.
*
* #param listener The listener to notify about changed selected values.
*/
public void setOnRangeSeekBarChangeListener(OnRangeSeekBarChangeListener<T> listener) {
this.listener = listener;
}
/**
* Handles thumb selection and movement. Notifies listener callback on certain events.
*/
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
int pointerIndex;
final int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// Remember where the motion event started
mActivePointerId = event.getPointerId(event.getPointerCount() - 1);
pointerIndex = event.findPointerIndex(mActivePointerId);
mDownMotionX = event.getX(pointerIndex);
pressedThumb = evalPressedThumb(mDownMotionX);
// Only handle thumb presses.
if (pressedThumb == null) {
return super.onTouchEvent(event);
}
setPressed(true);
invalidate();
onStartTrackingTouch();
trackTouchEvent(event);
attemptClaimDrag();
break;
case MotionEvent.ACTION_MOVE:
if (pressedThumb != null) {
if (mIsDragging) {
trackTouchEvent(event);
} else {
// Scroll to follow the motion event
pointerIndex = event.findPointerIndex(mActivePointerId);
final float x = event.getX(pointerIndex);
if (Math.abs(x - mDownMotionX) > mScaledTouchSlop) {
setPressed(true);
invalidate();
onStartTrackingTouch();
trackTouchEvent(event);
attemptClaimDrag();
}
}
if (notifyWhileDragging && listener != null) {
listener.onRangeSeekBarValuesChanged(this, getSelectedMinValue(), getSelectedMaxValue());
}
}
break;
case MotionEvent.ACTION_UP:
if (mIsDragging) {
trackTouchEvent(event);
onStopTrackingTouch();
setPressed(false);
} else {
// Touch up when we never crossed the touch slop threshold
// should be interpreted as a tap-seek to that location.
onStartTrackingTouch();
trackTouchEvent(event);
onStopTrackingTouch();
}
pressedThumb = null;
invalidate();
if (listener != null) {
listener.onRangeSeekBarValuesChanged(this, getSelectedMinValue(), getSelectedMaxValue());
}
break;
case MotionEvent.ACTION_POINTER_DOWN: {
final int index = event.getPointerCount() - 1;
// final int index = ev.getActionIndex();
mDownMotionX = event.getX(index);
mActivePointerId = event.getPointerId(index);
invalidate();
break;
}
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(event);
invalidate();
break;
case MotionEvent.ACTION_CANCEL:
if (mIsDragging) {
onStopTrackingTouch();
setPressed(false);
}
invalidate(); // see above explanation
break;
}
return true;
}
private final void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = (ev.getAction() & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose
// a new active pointer and adjust accordingly.
// TODO: Make this decision more intelligent.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mDownMotionX = ev.getX(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
}
private final void trackTouchEvent(MotionEvent event) {
final int pointerIndex = event.findPointerIndex(mActivePointerId);
final float x = event.getX(pointerIndex);
if (Thumb.MIN.equals(pressedThumb) && !mSingleThumb) {
setNormalizedMinValue(screenToNormalized(x));
} else if (Thumb.MAX.equals(pressedThumb)) {
setNormalizedMaxValue(screenToNormalized(x));
}
}
/**
* Tries to claim the user's drag motion, and requests disallowing any ancestors from stealing events in the drag.
*/
private void attemptClaimDrag() {
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
}
/**
* This is called when the user has started touching this widget.
*/
void onStartTrackingTouch() {
mIsDragging = true;
}
/**
* This is called when the user either releases his touch or the touch is canceled.
*/
void onStopTrackingTouch() {
mIsDragging = false;
}
/**
* Ensures correct size of the widget.
*/
#Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = 200;
if (MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(widthMeasureSpec)) {
width = MeasureSpec.getSize(widthMeasureSpec);
}
int height = thumbImage.getHeight() + PixelUtil.dpToPx(getContext(), HEIGHT_IN_DP);
if (MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(heightMeasureSpec)) {
height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
}
setMeasuredDimension(width, height);
}
/**
* Draws the widget on the given canvas.
*/
#Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setTextSize(mTextSize);
paint.setStyle(Style.FILL);
paint.setColor(Color.GRAY);
paint.setAntiAlias(true);
// draw min and max labels
String minLabel = getContext().getString(R.string.demo_min_label);
String maxLabel = getContext().getString(R.string.demo_max_label);
float minMaxLabelSize = Math.max(paint.measureText(minLabel), paint.measureText(maxLabel));
float minMaxHeight = mTextOffset + thumbHalfHeight + mTextSize / 3;
canvas.drawText(minLabel, 0, minMaxHeight, paint);
canvas.drawText(maxLabel, getWidth() - minMaxLabelSize, minMaxHeight, paint);
padding = INITIAL_PADDING + minMaxLabelSize + thumbHalfWidth;
// draw seek bar background line
mRect.left = padding;
mRect.right = getWidth() - padding;
canvas.drawRect(mRect, paint);
boolean selectedValuesAreDefault = (getSelectedMinValue().equals(getAbsoluteMinValue()) &&
getSelectedMaxValue().equals(getAbsoluteMaxValue()));
int colorToUseForButtonsAndHighlightedLine = selectedValuesAreDefault ?
Color.GRAY : // default values
DEFAULT_COLOR; //non default, filter is active
// draw seek bar active range line
mRect.left = normalizedToScreen(normalizedMinValue);
mRect.right = normalizedToScreen(normalizedMaxValue);
paint.setColor(colorToUseForButtonsAndHighlightedLine);
canvas.drawRect(mRect, paint);
// draw minimum thumb if not a single thumb control
if (!mSingleThumb) {
drawThumb(normalizedToScreen(normalizedMinValue), Thumb.MIN.equals(pressedThumb), canvas,
selectedValuesAreDefault);
}
// draw maximum thumb
drawThumb(normalizedToScreen(normalizedMaxValue), Thumb.MAX.equals(pressedThumb), canvas,
selectedValuesAreDefault);
// draw the text if sliders have moved from default edges
if (!selectedValuesAreDefault) {
paint.setTextSize(mTextSize);
paint.setColor(Color.WHITE);
// give text a bit more space here so it doesn't get cut off
int offset = PixelUtil.dpToPx(getContext(), TEXT_LATERAL_PADDING_IN_DP);
String minText = String.valueOf(getSelectedMinValue());
String maxText = String.valueOf(getSelectedMaxValue());
float minTextWidth = paint.measureText(minText) + offset;
float maxTextWidth = paint.measureText(maxText) + offset;
if (!mSingleThumb) {
canvas.drawText(minText,
normalizedToScreen(normalizedMinValue) - minTextWidth * 0.5f,
mDistanceToTop + mTextSize,
paint);
}
canvas.drawText(maxText,
normalizedToScreen(normalizedMaxValue) - maxTextWidth * 0.5f,
mDistanceToTop + mTextSize,
paint);
}
}
/**
* Overridden to save instance state when device orientation changes. This method is called automatically if you assign an id to the RangeSeekBar widget using the {#link #setId(int)} method. Other members of this class than the normalized min and max values don't need to be saved.
*/
#Override
protected Parcelable onSaveInstanceState() {
final Bundle bundle = new Bundle();
bundle.putParcelable("SUPER", super.onSaveInstanceState());
bundle.putDouble("MIN", normalizedMinValue);
bundle.putDouble("MAX", normalizedMaxValue);
return bundle;
}
/**
* Overridden to restore instance state when device orientation changes. This method is called automatically if you assign an id to the RangeSeekBar widget using the {#link #setId(int)} method.
*/
#Override
protected void onRestoreInstanceState(Parcelable parcel) {
final Bundle bundle = (Bundle) parcel;
super.onRestoreInstanceState(bundle.getParcelable("SUPER"));
normalizedMinValue = bundle.getDouble("MIN");
normalizedMaxValue = bundle.getDouble("MAX");
}
/**
* Draws the "normal" resp. "pressed" thumb image on specified x-coordinate.
*
* #param screenCoord The x-coordinate in screen space where to draw the image.
* #param pressed Is the thumb currently in "pressed" state?
* #param canvas The canvas to draw upon.
*/
private void drawThumb(float screenCoord, boolean pressed, Canvas canvas, boolean areSelectedValuesDefault) {
Bitmap buttonToDraw;
if (areSelectedValuesDefault) {
buttonToDraw = thumbDisabledImage;
} else {
buttonToDraw = pressed ? thumbPressedImage : thumbImage;
}
canvas.drawBitmap(buttonToDraw, screenCoord - thumbHalfWidth,
mTextOffset,
paint);
}
/**
* Decides which (if any) thumb is touched by the given x-coordinate.
*
* #param touchX The x-coordinate of a touch event in screen space.
* #return The pressed thumb or null if none has been touched.
*/
private Thumb evalPressedThumb(float touchX) {
Thumb result = null;
boolean minThumbPressed = isInThumbRange(touchX, normalizedMinValue);
boolean maxThumbPressed = isInThumbRange(touchX, normalizedMaxValue);
if (minThumbPressed && maxThumbPressed) {
// if both thumbs are pressed (they lie on top of each other), choose the one with more room to drag. this avoids "stalling" the thumbs in a corner, not being able to drag them apart anymore.
result = (touchX / getWidth() > 0.5f) ? Thumb.MIN : Thumb.MAX;
} else if (minThumbPressed) {
result = Thumb.MIN;
} else if (maxThumbPressed) {
result = Thumb.MAX;
}
return result;
}
/**
* Decides if given x-coordinate in screen space needs to be interpreted as "within" the normalized thumb x-coordinate.
*
* #param touchX The x-coordinate in screen space to check.
* #param normalizedThumbValue The normalized x-coordinate of the thumb to check.
* #return true if x-coordinate is in thumb range, false otherwise.
*/
private boolean isInThumbRange(float touchX, double normalizedThumbValue) {
return Math.abs(touchX - normalizedToScreen(normalizedThumbValue)) <= thumbHalfWidth;
}
/**
* Sets normalized min value to value so that 0 <= value <= normalized max value <= 1. The View will get invalidated when calling this method.
*
* #param value The new normalized min value to set.
*/
private void setNormalizedMinValue(double value) {
normalizedMinValue = Math.max(0d, Math.min(1d, Math.min(value, normalizedMaxValue)));
invalidate();
}
/**
* Sets normalized max value to value so that 0 <= normalized min value <= value <= 1. The View will get invalidated when calling this method.
*
* #param value The new normalized max value to set.
*/
private void setNormalizedMaxValue(double value) {
normalizedMaxValue = Math.max(0d, Math.min(1d, Math.max(value, normalizedMinValue)));
invalidate();
}
/**
* Converts a normalized value to a Number object in the value space between absolute minimum and maximum.
*
* #param normalized
* #return
*/
#SuppressWarnings("unchecked")
private T normalizedToValue(double normalized) {
double v = absoluteMinValuePrim + normalized * (absoluteMaxValuePrim - absoluteMinValuePrim);
// TODO parameterize this rounding to allow variable decimal points
return (T) numberType.toNumber(Math.round(v * 100) / 100d);
}
/**
* Converts the given Number value to a normalized double.
*
* #param value The Number value to normalize.
* #return The normalized double.
*/
private double valueToNormalized(T value) {
if (0 == absoluteMaxValuePrim - absoluteMinValuePrim) {
// prevent division by zero, simply return 0.
return 0d;
}
return (value.doubleValue() - absoluteMinValuePrim) / (absoluteMaxValuePrim - absoluteMinValuePrim);
}
/**
* Converts a normalized value into screen space.
*
* #param normalizedCoord The normalized value to convert.
* #return The converted value in screen space.
*/
private float normalizedToScreen(double normalizedCoord) {
return (float) (padding + normalizedCoord * (getWidth() - 2 * padding));
}
/**
* Converts screen space x-coordinates into normalized values.
*
* #param screenCoord The x-coordinate in screen space to convert.
* #return The normalized value.
*/
private double screenToNormalized(float screenCoord) {
int width = getWidth();
if (width <= 2 * padding) {
// prevent division by zero, simply return 0.
return 0d;
} else {
double result = (screenCoord - padding) / (width - 2 * padding);
return Math.min(1d, Math.max(0d, result));
}
}
/**
* Callback listener interface to notify about changed range values.
*
* #param <T> The Number type the RangeSeekBar has been declared with.
* #author Stephan Tittel (stephan.tittel#kom.tu-darmstadt.de)
*/
public interface OnRangeSeekBarChangeListener<T> {
public void onRangeSeekBarValuesChanged(RangeSeekBar<?> bar, T minValue, T maxValue);
}
/**
* Thumb constants (min and max).
*/
private static enum Thumb {
MIN, MAX
}
;
/**
* Utility enumeration used to convert between Numbers and doubles.
*
* #author Stephan Tittel (stephan.tittel#kom.tu-darmstadt.de)
*/
private static enum NumberType {
LONG, DOUBLE, INTEGER, FLOAT, SHORT, BYTE, BIG_DECIMAL;
public static <E extends Number> NumberType fromNumber(E value) throws IllegalArgumentException {
if (value instanceof Long) {
return LONG;
}
if (value instanceof Double) {
return DOUBLE;
}
if (value instanceof Integer) {
return INTEGER;
}
if (value instanceof Float) {
return FLOAT;
}
if (value instanceof Short) {
return SHORT;
}
if (value instanceof Byte) {
return BYTE;
}
if (value instanceof BigDecimal) {
return BIG_DECIMAL;
}
throw new IllegalArgumentException("Number class '" + value.getClass().getName() + "' is not supported");
}
public Number toNumber(double value) {
switch (this) {
case LONG:
return Long.valueOf((long) value);
case DOUBLE:
return value;
case INTEGER:
return Integer.valueOf((int) value);
case FLOAT:
return Float.valueOf((float)value);
case SHORT:
return Short.valueOf((short) value);
case BYTE:
return Byte.valueOf((byte) value);
case BIG_DECIMAL:
return BigDecimal.valueOf(value);
}
throw new InstantiationError("can't convert " + this + " to a Number object");
}
}
}
Ok, you can use the predefined library to acheive that, there will two Thumbs and you'll get left and right thumb value.
Use this Material Range Bar
I try to do my own version of "fruit ninja" for training based on this version : https://github.com/emmaguy/FruitNinja
I have done some minor changes. What I want to do is to affect different scores to the object in the "enum" in fruittype.
So, I add this function (in the aim to retrieve the current random value):
public static int currentrandom() {
return random.nextInt(FruitType2.values().length );
}
and I add,
if (FruitType2.currentrandom()<=9) {
score++;
} else {
score=score-5;
}
at the end of FruitProjectileManager.
Complete code for FruitProjectileManager:
public class FruitProjectileManager02 implements ProjectileManager {
private final Random random2 = new Random();
private final List<Projectile> fruitProjectiles =
new ArrayList<Projectile>();
private final SparseArray<Bitmap> bitmapCache;
private Region clip;
private int maxWidth;
private int maxHeight;
private String FruitTypen = "FruitType2";
public FruitProjectileManager02(Resources r) {
bitmapCache = new SparseArray<Bitmap>(FruitType2.values().length);
for (FruitType2 t : FruitType2.values()) {
bitmapCache.put(t.getResourceId(), BitmapFactory.decodeResource(r, t.getResourceId(), new Options()));
}
}
public void draw(Canvas canvas) {
for (Projectile f : fruitProjectiles) {
f.draw(canvas);
}
}
public void update() {
if (maxWidth < 0 || maxHeight < 0) {
return;
}
if (random2.nextInt(1000) < 30) {
fruitProjectiles.add(createNewFruitProjectile());
}
for (Iterator<Projectile> iter = fruitProjectiles.iterator(); iter.hasNext(); ) {
Projectile f = iter.next();
f.move();
if (f.hasMovedOffScreen()) {
iter.remove();
}
}
}
private FruitProjectile02 createNewFruitProjectile() {
int angle = random2.nextInt(20) + 70;
int speed = random2.nextInt(30) + 120;
boolean rightToLeft = random2.nextBoolean();
float gravity = random2.nextInt(6) + 8.0f;
float rotationStartingAngle = random2.nextInt(360);
float rotationIncrement = random2.nextInt(100) / 3.0f;
if (random2.nextInt(1) % 2 == 0) {
rotationIncrement *= -1;
}
return new FruitProjectile02(bitmapCache.get(FruitType2.randomFruit().getResourceId()), maxWidth, maxHeight,
angle, speed, gravity, rightToLeft, rotationIncrement, rotationStartingAngle);
}
public void setWidthAndHeight(int width, int height) {
this.maxWidth = width;
this.maxHeight = height;
this.clip = new Region(0, 0, width, height);
}
#Override
public int testForCollisions(List<TimedPath> allPaths) {
int score = 0;
for (TimedPath p : allPaths) {
for (Projectile f : fruitProjectiles) {
if (!f.isAlive())
continue;
Region projectile = new Region(f.getLocation());
Region path = new Region();
path.setPath(p, clip);
if (!projectile.quickReject(path) && projectile.op(path, Region.Op.INTERSECT)) {
if (FruitType2.currentrandom() <= 9) {
score++;
} else {
score = score - 5;
}
f.kill();
}
}
}
return score;
}
}
Complete code for FruitType:
public enum FruitType2 {
T02(R.drawable.n002),
T04(R.drawable.n004),
T06(R.drawable.n006),
T08(R.drawable.n008),
T10(R.drawable.n010),
T12(R.drawable.n012),
T14(R.drawable.n014),
T16(R.drawable.n016),
T18(R.drawable.n018),
T20(R.drawable.n020),
OTHER1(R.drawable.n003),
OTHER2(R.drawable.n007),
OTHER3(R.drawable.n011);
private final int resourceId;
private FruitType2(int resourceId) {
this.resourceId = resourceId;
}
public int getResourceId() {
return resourceId;
}
private static final Random random = new Random();
public static int currentrandom() {
return random.nextInt(FruitType2.values().length);
}
public static FruitType2 randomFruit() {
return FruitType2.values()[random.nextInt(FruitType2.values().length)];
}
}
I understand the problem , the current random(when the fruit is generated) is not the same that the random when the fruit is sliced and my question is how to
solve this problem. I get no idea so if you have some clues, I am interested.
Thank you in advance.
Perhaps i don't understand the problem, but why don't you store the random number in a variable? Later you can take the random number out of the variable.
I am Using https://github.com/TriggerTrap/SeekArc library its working fine if I set max value near 1000 but when i set max value = 100000000 then I am not able to seek at min or max value.
This is my code.
<com.hdfcclife.activities.SeekArc
android:id="#+id/seekArc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
seekarc:arcWidth="#dimen/seekwidth"
seekarc:progressWidth="#dimen/seekprowidth"
seekarc:arcColor="#android:color/white"
seekarc:clockwise="true"
android:layout_marginTop="#dimen/seektop"
seekarc:max="100000000"
seekarc:progressColor="#color/red"
seekarc:rotation="250"
seekarc:startAngle="62"
seekarc:sweepAngle="95"
seekarc:thumb="#drawable/custom_seek_arc_control_selector"
seekarc:touchInside="false"
/>
this is code.
public class SeekArc extends View {
private static final String TAG = SeekArc.class.getSimpleName();
private static int INVALID_PROGRESS_VALUE = -1;
// The initial rotational offset -90 means we start at 12 o'clock
private final int mAngleOffset = -90;
/**
* The Drawable for the seek arc thumbnail
*/
private Drawable mThumb;
/**
* The Maximum value that this SeekArc can be set to
*/
private long mMax = 100;
private int mMaxV = 100;
/**
* The Current value that the SeekArc is set to
*/
private long mProgress = 0;
private int mProg = 0;
/**
* The width of the progress line for this SeekArc
*/
private int mProgressWidth = 12;
/**
* The Width of the background arc for the SeekArc
*/
private int mArcWidth = 18;
/**
* The Angle to start drawing this Arc from
*/
private int mStartAngle = 0;
/**
* The Angle through which to draw the arc (Max is 360)
*/
private int mSweepAngle = 360;
/**
* The rotation of the SeekArc- 0 is twelve o'clock
*/
private int mRotation = 0;
/**
* Give the SeekArc rounded edges
*/
private boolean mRoundedEdges = false;
/**
* Enable touch inside the SeekArc
*/
private boolean mTouchInside = true;
/**
* Will the progress increase clockwise or anti-clockwise
*/
private boolean mClockwise = true;
// Internal variables
private int mArcRadius = 0;
private float mProgressSweep = 0;
private RectF mArcRect = new RectF();
private Paint mArcPaint;
private Paint mProgressPaint;
private int mTranslateX;
private int mTranslateY;
private int mThumbXPos;
private int mThumbYPos;
private double mTouchAngle;
private float mTouchIgnoreRadius;
private OnSeekArcChangeListener mOnSeekArcChangeListener;
public interface OnSeekArcChangeListener {
/**
* Notification that the progress level has changed. Clients can use the
* fromUser parameter to distinguish user-initiated changes from those
* that occurred programmatically.
*
* #param seekArc
* The SeekArc whose progress has changed
* #param progress
* The current progress level. This will be in the range
* 0..max where max was set by
* {#link ProgressArc#setMax(int)}. (The default value for
* max is 100.)
* #param fromUser
* True if the progress change was initiated by the user.
*/
void onProgressChanged(SeekArc seekArc, long progress, boolean fromUser);
/**
* Notification that the user has started a touch gesture. Clients may
* want to use this to disable advancing the seekbar.
*
* #param seekArc
* The SeekArc in which the touch gesture began
*/
void onStartTrackingTouch(SeekArc seekArc);
/**
* Notification that the user has finished a touch gesture. Clients may
* want to use this to re-enable advancing the seekarc.
*
* #param seekArc
* The SeekArc in which the touch gesture began
*/
void onStopTrackingTouch(SeekArc seekArc);
}
public SeekArc(Context context) {
super(context);
init(context, null, 0);
}
public SeekArc(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, R.attr.seekArcStyle);
}
public SeekArc(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
Log.d(TAG, "Initialising SeekArc");
final Resources res = getResources();
float density = context.getResources().getDisplayMetrics().density;
// Defaults, may need to link this into theme settings
int arcColor = res.getColor(R.color.progress_gray);
int progressColor = res.getColor(android.R.color.holo_blue_light);
int thumbHalfheight = 0;
int thumbHalfWidth = 0;
mThumb = res.getDrawable(R.drawable.seek_arc_control_selector);
// Convert progress width to pixels for current density
mProgressWidth = (int) (mProgressWidth * density);
if (attrs != null) {
// Attribute initialization
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SeekArc, defStyle, 0);
Drawable thumb = a.getDrawable(R.styleable.SeekArc_thumb);
if (thumb != null) {
mThumb = thumb;
}
thumbHalfheight = (int) mThumb.getIntrinsicHeight() / 2;
thumbHalfWidth = (int) mThumb.getIntrinsicWidth() / 2;
mThumb.setBounds(-thumbHalfWidth, -thumbHalfheight, thumbHalfWidth,
thumbHalfheight);
mMax = a.getInteger(R.styleable.SeekArc_max, mMaxV);
Integer mPro = a.getInteger(R.styleable.SeekArc_progress, mProg);
mProgress=new Long(mPro);
mProgressWidth = (int) a.getDimension(
R.styleable.SeekArc_progressWidth, mProgressWidth);
mArcWidth = (int) a.getDimension(R.styleable.SeekArc_arcWidth,
mArcWidth);
mStartAngle = a.getInt(R.styleable.SeekArc_startAngle, mStartAngle);
mSweepAngle = a.getInt(R.styleable.SeekArc_sweepAngle, mSweepAngle);
mRotation = a.getInt(R.styleable.SeekArc_rotation, mRotation);
mRoundedEdges = a.getBoolean(R.styleable.SeekArc_roundEdges,
mRoundedEdges);
mTouchInside = a.getBoolean(R.styleable.SeekArc_touchInside,
mTouchInside);
mClockwise = a.getBoolean(R.styleable.SeekArc_clockwise,
mClockwise);
arcColor = a.getColor(R.styleable.SeekArc_arcColor, arcColor);
progressColor = a.getColor(R.styleable.SeekArc_progressColor,
progressColor);
a.recycle();
}
mProgress = (mProgress > mMax) ? mMax : mProgress;
mProgress = (mProgress < 0) ? 0 : mProgress;
mSweepAngle = (mSweepAngle > 360) ? 360 : mSweepAngle;
mSweepAngle = (mSweepAngle < 0) ? 0 : mSweepAngle;
mStartAngle = (mStartAngle > 360) ? 0 : mStartAngle;
mStartAngle = (mStartAngle < 0) ? 0 : mStartAngle;
mArcPaint = new Paint();
mArcPaint.setColor(arcColor);
mArcPaint.setAntiAlias(true);
mArcPaint.setStyle(Paint.Style.STROKE);
mArcPaint.setStrokeWidth(mArcWidth);
mArcPaint.setStrokeMiter(5.5f);
//mArcPaint.setAlpha(45);
mProgressPaint = new Paint();
mProgressPaint.setColor(progressColor);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setStyle(Paint.Style.STROKE);
mProgressPaint.setStrokeWidth(mProgressWidth);
if (mRoundedEdges) {
mArcPaint.setStrokeCap(Paint.Cap.ROUND);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
}
}
#Override
protected void onDraw(Canvas canvas) {
if(!mClockwise) {
canvas.scale(-1, 1, mArcRect.centerX(), mArcRect.centerY() );
}
// Draw the arcs
final int arcStart = mStartAngle + mAngleOffset + mRotation;
final int arcSweep = mSweepAngle;
canvas.drawArc(mArcRect, arcStart, arcSweep, false, mArcPaint);
canvas.drawArc(mArcRect, arcStart, mProgressSweep, false,
mProgressPaint);
// Draw the thumb nail
canvas.translate(mTranslateX -mThumbXPos, mTranslateY -mThumbYPos);
mThumb.draw(canvas);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int height = getDefaultSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
final int width = getDefaultSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
final int min = Math.min(width, height);
float top = 0;
float left = 0;
int arcDiameter = 0;
mTranslateX = (int) (width * 0.5f);
mTranslateY = (int) (height * 0.5f);
arcDiameter = min - getPaddingLeft();
mArcRadius = arcDiameter / 2;
top = (height / 2 - (arcDiameter / 2));
left = width / 2 - (arcDiameter / 2);
mArcRect.set(left, top, left + arcDiameter, top + arcDiameter);
int arcStart = (int)mProgressSweep + mStartAngle + mRotation + 90;
mThumbXPos = (int) (mArcRadius * Math.cos(Math.toRadians(arcStart)));
mThumbYPos = (int) (mArcRadius * Math.sin(Math.toRadians(arcStart)));
setTouchInSide(mTouchInside);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
onStartTrackingTouch();
updateOnTouch(event);
break;
case MotionEvent.ACTION_MOVE:
updateOnTouch(event);
break;
case MotionEvent.ACTION_UP:
onStopTrackingTouch();
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL:
onStopTrackingTouch();
setPressed(false);
break;
}
return true;
}
#Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (mThumb != null && mThumb.isStateful()) {
int[] state = getDrawableState();
mThumb.setState(state);
}
invalidate();
}
private void onStartTrackingTouch() {
if (mOnSeekArcChangeListener != null) {
mOnSeekArcChangeListener.onStartTrackingTouch(this);
}
}
private void onStopTrackingTouch() {
if (mOnSeekArcChangeListener != null) {
mOnSeekArcChangeListener.onStopTrackingTouch(this);
}
}
private void updateOnTouch(MotionEvent event) {
boolean ignoreTouch = ignoreTouch(event.getX(), event.getY());
if (ignoreTouch) {
return;
}
setPressed(true);
mTouchAngle = getTouchDegrees(event.getX(), event.getY());
int progress = getProgressForAngle(mTouchAngle);
onProgressRefresh(progress, true);
}
private boolean ignoreTouch(float xPos, float yPos) {
boolean ignore = false;
float x = xPos - mTranslateX;
float y = yPos - mTranslateY;
float touchRadius = (float) Math.sqrt(((x * x) + (y * y)));
if (touchRadius < mTouchIgnoreRadius) {
ignore = true;
}else if(touchRadius>mArcRadius+40)
{
ignore = true;
}
return ignore;
}
private double getTouchDegrees(float xPos, float yPos) {
float x = xPos - mTranslateX;
float y = yPos - mTranslateY;
//invert the x-coord if we are rotating anti-clockwise
x= (mClockwise) ? x:-x;
// convert to arc Angle
double angle = Math.toDegrees(Math.atan2(y, x) + (Math.PI / 2)
- Math.toRadians(mRotation));
if (angle < 0) {
angle = 360 + angle;
}
angle -= mStartAngle;
return angle;
}
private int getProgressForAngle(double angle) {
int touchProgress = (int) Math.round(valuePerDegree() * angle);
touchProgress = (touchProgress < 0) ? INVALID_PROGRESS_VALUE
: touchProgress;
touchProgress = (touchProgress > mMax) ? INVALID_PROGRESS_VALUE
: touchProgress;
return touchProgress;
}
private float valuePerDegree() {
return (float) mMax / mSweepAngle;
}
private void onProgressRefresh(int progress, boolean fromUser) {
updateProgress(progress, fromUser);
}
private void updateThumbPosition() {
int thumbAngle = (int) (mStartAngle + mProgressSweep + mRotation + 90);
mThumbXPos = (int) (mArcRadius * Math.cos(Math.toRadians(thumbAngle)));
mThumbYPos = (int) (mArcRadius * Math.sin(Math.toRadians(thumbAngle)));
}
private void updateProgress(long progress, boolean fromUser) {
if (progress == INVALID_PROGRESS_VALUE) {
return;
}
if (mOnSeekArcChangeListener != null) {
mOnSeekArcChangeListener
.onProgressChanged(this, progress, fromUser);
}
progress = (progress > mMax) ? mMax : progress;
progress = (mProgress < 0) ? 0 : progress;
mProgress = (int) progress;
mProgressSweep = (float) progress / mMax * mSweepAngle;
updateThumbPosition();
invalidate();
}
/**
* Sets a listener to receive notifications of changes to the SeekArc's
* progress level. Also provides notifications of when the user starts and
* stops a touch gesture within the SeekArc.
*
* #param l
* The seek bar notification listener
*
* #see SeekArc.OnSeekBarChangeListener
*/
public void setOnSeekArcChangeListener(OnSeekArcChangeListener l) {
mOnSeekArcChangeListener = l;
}
public void setProgress(long progress) {
updateProgress(progress, false);
}
public void setMax(long progress) {
mMax=progress;
invalidate();
}
public int getProgressWidth() {
return mProgressWidth;
}
public void setProgressWidth(int mProgressWidth) {
this.mProgressWidth = mProgressWidth;
mProgressPaint.setStrokeWidth(mProgressWidth);
}
public int getArcWidth() {
return mArcWidth;
}
public void setArcWidth(int mArcWidth) {
this.mArcWidth = mArcWidth;
mArcPaint.setStrokeWidth(mArcWidth);
}
public int getArcRotation() {
return mRotation;
}
public void setArcRotation(int mRotation) {
this.mRotation = mRotation;
updateThumbPosition();
}
public int getStartAngle() {
return mStartAngle;
}
public void setStartAngle(int mStartAngle) {
this.mStartAngle = mStartAngle;
updateThumbPosition();
}
public int getSweepAngle() {
return mSweepAngle;
}
public void setSweepAngle(int mSweepAngle) {
this.mSweepAngle = mSweepAngle;
updateThumbPosition();
}
public void setRoundedEdges(boolean isEnabled) {
mRoundedEdges = isEnabled;
if (mRoundedEdges) {
mArcPaint.setStrokeCap(Paint.Cap.ROUND);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
} else {
mArcPaint.setStrokeCap(Paint.Cap.SQUARE);
mProgressPaint.setStrokeCap(Paint.Cap.SQUARE);
}
}
public void setTouchInSide(boolean isEnabled) {
int thumbHalfheight = (int) mThumb.getIntrinsicHeight() / 2;
int thumbHalfWidth = (int) mThumb.getIntrinsicWidth() / 2;
mTouchInside = isEnabled;
if (mTouchInside) {
mTouchIgnoreRadius = (float) mArcRadius / 4;
} else {
// Don't use the exact radius makes interaction too tricky
mTouchIgnoreRadius = mArcRadius
- Math.min(thumbHalfWidth, thumbHalfheight);
}
}
public void setClockwise(boolean isClockwise) {
mClockwise = isClockwise;
}
}
Please change the following code in "SeekArc" class
private long mMax = 100;
private int mMaxV = 100;
to
private long mMax = 100000000;
private int mMaxV = 100000000;
This should fix it, else let me know what the result is...
Im working on a program, pretty simple. You simple enter a person's name into the field provided. click search and it searches a database and retrieves information. Including the picture. this works fine but i have one problem. If i do a search using peter and there are two 'peters' in the database. When i scroll. the picture does not change unless i click the picture field. I believe i posted the relavant code. Any help will be appreciated. Thank you
public class DriverSearchResultScreen extends MainScreen implements FieldChangeListener{
LabelField header,title;
LabelField lblLicenseNumber,lblFirstName,lblLastName,lblBirthDate,lblLicenseExpiry,lblLicenseType,lblLicenseStatus;
ColoredMultiLineLabelField clblLicenseNumber,clblFirstName,clblLastName,clblBirthDate,clblLicenseExpiry,clblLicenseType,clblLicenseStatus;
CustomButtonField btnSearch;
CustomImageButton btnLeft,btnRight;
CustomImageButton bmpfDriverPhoto;
Vector licenseInfoData;
int currentIndex = 0;
public DriverSearchResultScreen(Vector licenseInfoData ) {
this.licenseInfoData = licenseInfoData;
// TODO Auto-generated constructor stub
title = new LabelField("License",LabelField.USE_ALL_WIDTH);
/*header.setBackground(bg);*/
setTitle(title);
bmpfDriverPhoto = new CustomImageButton(Bitmap.getBitmapResource("default-profile.png")){
public boolean isFocusable() { return true; };
};
bmpfDriverPhoto.setChangeListener(this);
add(bmpfDriverPhoto);
header = new LabelField("",LabelField.FIELD_HCENTER|LabelField.USE_ALL_WIDTH){
public void paint(Graphics g){
int col = g.getColor();
g.setColor(Color.YELLOW);
super.paint(g);
g.setColor(col);
}
public int getPreferredWidth(){
return net.rim.device.api.system.Display.getWidth();
}
};
this.getMainManager().setBackground(BackgroundFactory.createBitmapBackground(Bitmap.getBitmapResource("background.png")));
header.setFont(Font.getDefault().derive(Font.SANS_SERIF_STYLE|Font.BOLD,25));
add(header);
add(new SeparatorField());
Bitmap vfmBackground = Bitmap.getBitmapResource("rounded-border.png");
VerticalFieldManager vfm = new VerticalFieldManager();
vfm.setBorder(BorderFactory.createBitmapBorder(new XYEdges(12,12,12,12),vfmBackground));
BHorizontalFieldManager hfm = new BHorizontalFieldManager();
lblFirstName= new LabelField("First Name :");
hfm.add(lblFirstName);
clblFirstName = new ColoredMultiLineLabelField("Jhon",Color.GRAY);
hfm.add(clblFirstName);
vfm.add(hfm);
vfm.add(new SeparatorField());
BHorizontalFieldManager hfm1 = new BHorizontalFieldManager();
lblLastName= new LabelField("Last Name :");
hfm1.add(lblLastName);
clblLastName = new ColoredMultiLineLabelField("Doe",Color.GRAY);
hfm1.add(clblLastName);
vfm.add(hfm1);
vfm.add(new SeparatorField());
BHorizontalFieldManager hfm2 = new BHorizontalFieldManager();
lblBirthDate = new LabelField("Date Of Birth:");
hfm2.add(lblBirthDate);
clblBirthDate = new ColoredMultiLineLabelField("11-June-1982",Color.GRAY);
hfm2.add(clblBirthDate);
vfm.add(hfm2);
vfm.add(new SeparatorField());
BHorizontalFieldManager hfm3 = new BHorizontalFieldManager();
lblLicenseNumber = new LabelField("License Number :");
hfm3.add(lblLicenseNumber);
clblLicenseNumber = new ColoredMultiLineLabelField("999999",Color.GRAY);
hfm3.add(clblLicenseNumber);
vfm.add(hfm3);
vfm.add(new SeparatorField());
BHorizontalFieldManager hfm4 = new BHorizontalFieldManager();
lblLicenseType = new LabelField("License Type :");
hfm4.add(lblLicenseType);
clblLicenseType = new ColoredMultiLineLabelField("B",Color.GRAY);
hfm4.add(clblLicenseType);
vfm.add(hfm4);
vfm.add(new SeparatorField());
BHorizontalFieldManager hfm5 = new BHorizontalFieldManager();
lblLicenseExpiry = new LabelField("Expiry Date:");
hfm5.add(lblLicenseExpiry);
clblLicenseExpiry = new ColoredMultiLineLabelField("25-Aug-2012",Color.GRAY);
hfm5.add(clblLicenseExpiry);
vfm.add(hfm5);
vfm.add(new SeparatorField());
BHorizontalFieldManager hfm6 = new BHorizontalFieldManager();
lblLicenseStatus = new LabelField("Licenes Status:");
hfm6.add(lblLicenseStatus);
clblLicenseStatus = new ColoredMultiLineLabelField("Expired",Color.GRAY);
hfm6.add(clblLicenseStatus);
vfm.add(hfm6);
vfm.add(new SeparatorField());
add(vfm);
btnLeft = new CustomImageButton(Bitmap.getBitmapResource("left-arrow-enable.png"),Bitmap.getBitmapResource("left-arrow-disable.png"));
btnRight= new CustomImageButton(Bitmap.getBitmapResource("right-arrow-enable.png"),Bitmap.getBitmapResource("right-arrow-disable.png"));;
HorizontalFieldManager arrowButtonHfm = new HorizontalFieldManager(){
public int getPreferredHeight() {
// TODO Auto-generated method stub
return btnLeft.getPreferredHeight()*2;
}
public int getPreferredWidth() {
// TODO Auto-generated method stub
return Display.getWidth();
}
protected void sublayout(int maxWidth, int maxHeight) {
// TODO Auto-generated method stub
int count = getFieldCount();
for(int i = 0 ; i < count ; i++ ){
Field f = getField(i);
if(f == btnLeft ){
setPositionChild(f, (getPreferredWidth() >> 1) - f.getPreferredWidth() - 30, getPreferredHeight()>>1);
}else if (f == btnRight ){
setPositionChild(f, (getPreferredWidth() >> 1) + 30, getPreferredHeight()>>1);
}
layoutChild(f, getPreferredWidth(), getPreferredHeight());
}
setExtent(getPreferredWidth(),getPreferredHeight());
}
public void subpaint(Graphics graphics){
int count = getFieldCount();
for(int i = 0 ; i < count ; i++ ){
net.rim.device.api.ui.Field f = getField(i);
paintChild(graphics,f);
}
}
};
/*add(new LabelField(){
public int getPreferredHeight() {
return 10;
}
});*/
btnLeft.setChangeListener(this);
btnRight.setChangeListener(this);
btnLeft.setEnabled(false);
arrowButtonHfm.add(btnLeft);
arrowButtonHfm.add(btnRight);
add(arrowButtonHfm);
fillLicenseHolderInfoToField((LicenseObject)licenseInfoData.elementAt(currentIndex));
setHeaderText();
enableDisableButtons();
}
private void setHeaderText(){
header.setText("Search Results. ( "+(currentIndex+1)+ " of "+ (licenseInfoData.size())+" )");
}
private void fillLicenseHolderInfoToField(LicenseObject licenseObject){
bmpfDriverPhoto.setImage(licenseObject.getBmpImage());
clblLicenseNumber.setText(licenseObject.getLicenseNum());
clblFirstName.setText(licenseObject.getFirstName());
clblLastName.setText(licenseObject.getLastName());
clblBirthDate.setText(licenseObject.getDateOfBirth());
clblLicenseExpiry.setText(licenseObject.getDateOfExpiry());
clblLicenseType.setText(licenseObject.getLicenseType());
clblLicenseStatus.setText(licenseObject.getLicenseStatus());
}
public void fieldChanged(Field field, int context) {
// TODO Auto-generated method stub
if(field == btnRight){
if( currentIndex < (licenseInfoData.size() - 1)){
currentIndex++;
fillLicenseHolderInfoToField((LicenseObject)licenseInfoData.elementAt(currentIndex));
}
}else if(field == btnLeft){
if( currentIndex > 0 ){
currentIndex--;
fillLicenseHolderInfoToField((LicenseObject)licenseInfoData.elementAt(currentIndex));
}
}else if( field == bmpfDriverPhoto ){
ImagePopDialog dialog = new ImagePopDialog("loader-image-box.png");
Bitmap scaledBitmap = new Bitmap(300, 300);
Bitmap btnBitmap = bmpfDriverPhoto.getImage();
btnBitmap.scaleInto(0, 0, btnBitmap.getWidth(), btnBitmap.getHeight(),
scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), 1);
dialog.add(scaledBitmap);
UiApplication.getUiApplication().pushScreen(dialog);
}
enableDisableButtons();
setHeaderText();
}
private void enableDisableButtons(){
btnLeft.setEnabled((currentIndex > 0)?true:false);
btnRight.setEnabled((currentIndex < (licenseInfoData.size() - 1))?true:false);
}
protected boolean onSavePrompt() {
// TODO Auto-generated method stub
return true;
}
}
//Custom Image Button
package com.app.ui.component;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.TouchEvent;
/**
* *
* Class to Draw an Image Button
*/
public class CustomImageButton extends Field {
/** Bitmap for enabled image */
private Bitmap bmpEnabled;
/** Bitmap for disabled image */
private Bitmap bmpDisabled;
/** Label for Button*/
private String label;
private boolean mEnabled=true;
private int mCurrentTouchX = 0;
private int mCurrentTouchY = 0;
/**
* Constructor with
* #param image
*/
public CustomImageButton(Bitmap image) {
super(Field.FOCUSABLE);
this.bmpEnabled = image;
}
/**
* Constructor with
* #param enabled
* #param disabled
*/
public CustomImageButton(Bitmap enabled,Bitmap disabled) {
this(enabled);
this.bmpDisabled = disabled;
}
public CustomImageButton(Bitmap enabled, Bitmap disabled, String label) {
this(enabled);
this.bmpDisabled = disabled;
this.label = label;
}
protected void layout(int height, int width) {
height = getPreferredHeight();
width = getPreferredWidth();
setExtent(width,height);
}
protected void paint(Graphics graphics) {
if( isEnabled() ){
if(isFocus()){
int col = graphics.getColor();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, getPreferredHeight(), getPreferredHeight());
graphics.setColor(col);
}
graphics.drawBitmap(5, 5, bmpEnabled.getWidth(), bmpEnabled.getHeight(), bmpEnabled,
0, 0);
if(label != null && !label.equals("")) {
graphics.setColor(Color.BLACK);
graphics.drawText(label, bmpEnabled.getWidth()+5, (getPreferredHeight() - getFont().getHeight())/2);
}
}else{
if( bmpDisabled != null )
graphics.drawBitmap(5, 5, bmpDisabled.getWidth(), bmpDisabled.getHeight(), bmpDisabled,
0, 0);
if(label != null && !label.equals("")) {
graphics.setColor(Color.LIGHTGRAY);
graphics.drawText(label, bmpEnabled.getWidth()+5, (getPreferredHeight() - getFont().getHeight())/2);
}
}
}
public int getPreferredWidth() {
int prefwidth = 0;
if(bmpEnabled != null) {
prefwidth = bmpEnabled.getWidth();
}
if(label != null && !label.equals("")) {
prefwidth = Display.getWidth()+10;
}
return (prefwidth+10);
}
public int getPreferredHeight() {
if(bmpEnabled != null) {
return bmpEnabled.getHeight()+10;
}
return 0;
}
/*protected boolean navigationClick(int status, int time) {
fieldChangeNotify(0);
return true;
}*/
/**
* To set the focused background color and invalidating the entire screen
*/
protected void onFocus(int direction) {
invalidate();
}
/**
* To set the unfocused background color and invalidating the entire screen
*/
protected void onUnfocus() {
invalidate();
}
/**
* Draws the focus indicator for this field.
* #param graphics
* #param on
*/
protected void drawFocus(Graphics graphics, boolean on) {
super.drawFocus(graphics, on);
}
protected boolean navigationClick(int status, int time){
if( mEnabled ){
if (mCurrentTouchX >= 0 && mCurrentTouchX <= getPreferredWidth()
&& mCurrentTouchY >= 0
&& mCurrentTouchY <= getPreferredHeight())
fieldChangeNotify(1);
mCurrentTouchX = 0;
mCurrentTouchY = 0;
return true;
}else{
return false;
}
}
protected boolean touchEvent(TouchEvent message) {
if (mEnabled) {
if (message.getEvent() == TouchEvent.CLICK) {
mCurrentTouchX = message.getX(1);
mCurrentTouchY = message.getY(1);
}
}
return super.touchEvent(message);
}
public void setEnabled(boolean enabled) {
// TODO Auto-generated method stub
super.setEnabled(enabled);
if(!enabled)
this.focusRemove();
}
public void setImage(Bitmap image){
this.bmpEnabled = image;
}
public Bitmap getImage(){
return this.bmpEnabled;
}
}
In your CustomImageButton class you should change your setImage method:
public void setImage(Bitmap image){
this.bmpEnabled = image;
}
by adding an invalidate to cause a redraw:
public void setImage(Bitmap image){
this.bmpEnabled = image;
invalidate();
}
The problem is that when your image is replaced, the change isn't seen on screen until the screen has been refreshed. invalidate() triggers a refresh of the screen(or layout), allowing any updates to be seen.
When you scroll or select the image, the invalidate() method is getting called so as the screen refreshes, which is why it isn't updating until then. A manual trigger of invalidate() solves this problem.
Make sure you are doing it on the Event Thread.