android onclick for several custom Views issue - android

Good morning, I'm drawing 9 customViews in one ralativeLayout.
I want then to assign on click listener for each view.
The issue is that when i click on one of these view, I get the reference to the last drawed view, even if I actually clicked on the first one.
Here is my code:
public class MainActivity extends Activity {
MySurfaceView view;
RelativeLayout layout;
List<CustomCircles> circlesArr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = (RelativeLayout) findViewById(R.id.relativeLayout);
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int width = layout.getMeasuredWidth();
int height = layout.getMeasuredHeight();
int radius = calculateCircleRadius(height);
calculateCirclesPosition(radius);
}
});
}
int circlesPerRow = 3;
int rows = 3;
private void calculateCirclesPosition(int radius) {
int index = 0;
circlesArr = new ArrayList<CustomCircles>();
for (int i = 0; i < rows; ++i) {
int y = radius + ((radius * 2) * i);
RelativeLayout.LayoutParams params = null;
if(i == 0) {
params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
} else if(i == 1) {
params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, circlesArr.get(0).id);
} else if(i == 2) {
params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, circlesArr.get(3).id);
}
for (int j = 0; j < circlesPerRow; ++j) {
int x = radius + ((radius * 2) * j);
Punto centro = new Punto(x, y);
Cerchio cerchio = new Cerchio(centro, radius);
cerchio.indexInArray = index;
CirclesHandler.get().getCircleList().add(cerchio);
CustomCircles circle = new CustomCircles(this, centro,
radius, index++);
circle.setTag("circle" + index);
Log.v("jajaja", "setted index is "+ index);
circlesArr.add(circle);
if(j == 0) {
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
} else {
params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.RIGHT_OF, circlesArr.get(j-1).getId());
}
layout.addView(circle, params);
}
}
}
private int calculateCircleRadius(int height) {
return (height / 3) / 2;
}
}
CustomCircleView Class
public class CustomCircles extends View implements View.OnClickListener {
Punto centro;
Paint paint;
int radius;
int id;
public CustomCircles(Context context, Punto centro, int radius, int id) {
this(context);
this.centro = centro;
this.radius = radius;
this.id = id;
//setId(id);
}
public CustomCircles(Context context) {
super(context);
init();
}
public CustomCircles(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomCircles(Context context, AttributeSet attrs) {
super(context, attrs);
}
private void init() {
this.setOnClickListener(this);
paint = new Paint();
paint.setColor(Color.parseColor("#000000"));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(centro.x, centro.y, radius, paint);
}
#Override
public void onClick(View v) {
Log.v("jajaja", "Clicked " + this.getTag());
}
}
Thank you for your time

You are putting your circles in RelativeLayout without options about place, thats why they all can have getLeft()==0 and getTop()==0.
For all circles call View method setId(index) and for LayoutParams need to add rules:
params.addRule(RelativeLayout.RIGHT_OF, prevCircle.getId());
params.addRule(RelativeLayout.ALIGN_TOP, prevCircle.getId());
or
params.addRule(RelativeLayout.BELOW, circleAbove.getId());
params.addRule(RelativeLayout.ALIGN_LEFT, circleAbove.getId());
for a new circle in line.

After few days I've tried to change my approach, using onMeasure() and onLayout().
Finally I've got it!
I'd like to share my code:
Custum relative layout class:
public class CustomRelativeLayout extends RelativeLayout {
public CustomRelativeLayout(Context context) {
super(context);
}
public CustomRelativeLayout(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public CustomRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < getChildCount(); ++i) {
View v = getChildAt(i);
Punto center = ((CustomCircles) v).centro;
int radius = ((CustomCircles) v).radius;
v.layout(center.x - radius, center.y - radius, center.x + radius,
center.y + radius);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
for (int i = 0; i < getChildCount(); ++i) {
View v = getChildAt(i);
Punto center = ((CustomCircles)v).centro;
v.measure(center.x * 2, center.y *2);
}
int desiredWidth = 100;
int desiredHeight = 100;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
} else {
//Be whatever you want
width = desiredWidth;
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
setMeasuredDimension(width, height);
}
}
custom circles class:
public class CustomCircles extends View implements View.OnClickListener {
Punto centro;
Paint paint;
int radius;
int id;
public CustomCircles(Context context, Punto centro, int radius, int id) {
this(context);
this.centro = centro;
this.radius = radius;
this.id = id;
}
public CustomCircles(Context context) {
super(context);
init();
}
public CustomCircles(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomCircles(Context context, AttributeSet attrs) {
super(context, attrs);
}
private void init() {
this.setOnClickListener(this);
paint = new Paint();
paint.setColor(Color.parseColor("#000000"));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(radius, radius, radius, paint);
}
private void changeColor() {
this.paint.setColor(Color.parseColor("#0000FF"));
invalidate();
}
#Override
public void onClick(View v) {
changeColor();
}
}
main activity class:
public class MainActivity extends Activity {
MySurfaceView view;
CustomRelativeLayout layout;
List<CustomCircles> circlesArr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = (CustomRelativeLayout) findViewById(R.id.customRelativeLayout);
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int width = layout.getMeasuredWidth();
int height = layout.getMeasuredHeight();
int radius = calculateCircleRadius(height);
calculateCirclesPosition(radius);
}
});
}
int circlesPerRow = 3;
int rows = 3;
private void calculateCirclesPosition(int radius) {
int index = 0;
circlesArr = new ArrayList<CustomCircles>();
for (int i = 0; i < rows; ++i) {
int y = radius + ((radius * 2) * i);
for (int j = 0; j < circlesPerRow; ++j) {
int x = radius + ((radius * 2) * j);
Punto centro = new Punto(x, y);
Cerchio cerchio = new Cerchio(centro, radius);
cerchio.indexInArray = index;
CirclesHandler.get().getCircleList().add(cerchio);
CustomCircles circle = new CustomCircles(this, centro,
radius, index++);
circlesArr.add(circle);
layout.addView(circle);
}
}
}
private int calculateCircleRadius(int height) {
return (height / 3) / 2;
}
}

Related

Ondraw Method doesnt call Using Viewpager & FragmentStateAdapter

I use a Custom Calendar View using
Viewpager - FragmentStateAdapter - Fragment - Viewgroup -view
I can get first fragment and second fragment when I swipe page, but third fragment doesn't show anything. so I debug and get draw() method doesn't call on View class.
I use Invalidate(), setWillNotDraw(false) but it doesn't work.
I saw in the log that fragment cycle operates fine. I don't know what the problem is.
Here is my code:
FragmentActivity
public class FindClassFragmentActivity extends FragmentActivity {
private static final int COUNT_PAGE = 12;
ViewPager mViewPager;
CalendarFragmentStatePagerAdapter calendarAdapter;
ImageButton previous;
ImageButton next;
TextView presentMonth;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.findclass_main_layout);
mViewPager = (ViewPager) findViewById(R.id.viewpager);
previous = (ImageButton) findViewById(R.id.previous_month);
next = (ImageButton) findViewById(R.id.next_month);
presentMonth = (TextView) findViewById(R.id.present_month);
calendarAdapter = new CalendarFragmentStatePagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(calendarAdapter);
// mViewPager.setOffscreenPageLimit(24);
}
public void PrevOrNext(View v) {
switch (v.getId()) {
case R.id.previous_month :
break;
case R.id.next_month :
break;
}
}
}
FragmentStatePagerAdapter
public class CalendarFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
private HashMap<Integer, MonthFragment> monthMap;
private int numOfMonth;
public CalendarFragmentStatePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return 24;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Log.e("solme6", "instantiateItem : " + position );
return super.instantiateItem(container, position);
}
#Override
public Fragment getItem(int position) {
return MonthFragment.newInstance(position);
}
}
CalendarMonthView
public class CalendarMonthView extends ViewGroup {
private final int mScreenWidth;
private final int mWidthDate;
private int mDateOfWeek; // 1일의 요일
private int mDefaultTextSize = 40;
private int mTextColor = Color.BLUE;
public static String[] DAY_OF_WEEK = null;
public CalendarMonthView(Context context, AttributeSet attrs) {
super(context, attrs);
mScreenWidth = getResources().getDisplayMetrics().widthPixels;
mWidthDate = mScreenWidth / 7;
DAY_OF_WEEK = getResources().getStringArray(R.array.day_of_week);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
Log.e("solme",Integer.toString(count));
int maxHeight = 0;
int childState = 0;
int childViewFullWidth = 0;
int childViewFullheight = 0;
for(int i=0; i < count; i++) {
final View child = getChildAt(i);
getChildAt(i).setWillNotDraw(false);
if (child.getVisibility() == GONE) {
continue;
}
childViewFullWidth = child.getMeasuredWidth();
childViewFullheight = child.getMeasuredHeight();
measureChild(child, widthMeasureSpec, heightMeasureSpec); // 자식의 크기 측정.
childState = combineMeasuredStates(childState, child.getMeasuredState());
}
setMeasuredDimension(childViewFullWidth, childViewFullheight);
LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
params.height = maxHeight;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
int curLeft = 0; // 왼쪽 스타트 지점 값.
int curTop = 0;
int eachCellWidth, eachCellHeight;
int curDayHeight;
final int childWidth = this.getMeasuredWidth(); // 1440
final int childHeight = this.getMeasuredHeight(); //2355
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE)
return;
child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST));
eachCellWidth = mWidthDate;
curDayHeight = 100;
eachCellHeight = (getMeasuredHeight() - curDayHeight) / 6;
if (i < 7) {
child.layout(curLeft, curTop, curLeft + eachCellWidth, curTop + curDayHeight);
curLeft += eachCellWidth;
if (curLeft + eachCellWidth >= childWidth) {
curLeft = 0;
curTop += curDayHeight;
}
} else {
if (i == 7) {
curLeft = (mDateOfWeek - 1) * eachCellWidth;
}
child.layout(curLeft, curTop, curLeft + eachCellWidth, curTop + eachCellHeight);
curLeft += eachCellWidth;
if (curLeft + eachCellWidth >= childWidth) {
curLeft = 0;
curTop += eachCellHeight;
}
}
}
}
#Override
protected void onDraw(Canvas canvas) {
Log.e("solme6", "CalendarMonthView : onDraw");
super.onDraw(canvas);
}
#Override
public void draw(Canvas canvas) {
Log.e("solme6", "CalendarMonthView : draw");
super.draw(canvas);
}
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
}
private Paint makePaint(int color) {
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(color);
p.setTextSize(mDefaultTextSize);
return p;
}
public void initCalendar(int dayOfWeek, int maxDateOfMonth) {
mDateOfWeek = dayOfWeek;
}
}
CalendarcellView
public class CalendarCellView extends View {
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
Paint mPaintTextWhite = new Paint(Paint.ANTI_ALIAS_FLAG);
Paint mPaintBackground = new Paint(Paint.ANTI_ALIAS_FLAG);
Paint mPaintBackgroundToday = new Paint(Paint.ANTI_ALIAS_FLAG);
Paint mPaintBackgroundEvent = new Paint(Paint.ANTI_ALIAS_FLAG);
private int dayOfWeek = -1;
private boolean isStaticText = false;
private long millis;
private Rect rect;
private boolean isTouchMode;
private int dp11;
private int dp16;
private boolean hasEvent = false;
private int[] mColorEvents;
private final float RADIUS = 100f;
public CalendarCellView(Context context) {
super(context);
initialize(context);
Log.e("solme6", "CalendarCellView : constructor");
}
public CalendarCellView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context);
}
private void initialize(Context context) {
dp11 = (int) dp2px(getContext(), 11);
dp16 = (int) dp2px(getContext(), 16);
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(dp11);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaintTextWhite.setColor(Color.WHITE);
mPaintTextWhite.setTextSize(dp11);
mPaintTextWhite.setTextAlign(Paint.Align.CENTER);
mPaintBackground.setColor(ContextCompat.getColor(getContext(), R.color.colorPrimaryDark));
mPaintBackgroundToday.setColor(ContextCompat.getColor(getContext(), R.color.today));
mPaintBackgroundEvent.setColor(ContextCompat.getColor(getContext(), R.color.colorPrimary));
setPadding(30, 0, 30, 0);
}
public float dp2px(Context context, float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.e("solme6","CalendarCellView : onMeasure");
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Log.e("solme6", "CalendarCellView : onLayout");
super.onLayout(changed, left, top, right, bottom);
}
#Override
protected void dispatchDraw(Canvas canvas) {
Log.e("solme6", "CalendarCellView : dispatchDraw");
}
#Override
public void draw(Canvas canvas) {
Log.e("solme6", "CalendarCellView : draw");
super.draw(canvas);
}
#Override
protected void onDraw(Canvas canvas) {
Log.e("solme6", "CalendarCellView : onDraw");
super.onDraw(canvas);
int xPos = (canvas.getWidth() / 2);
int yPos = (int) ((canvas.getHeight() / 2) - ((mPaint.descent() + mPaint.ascent()) / 2));
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(millis);
set
CalendarMonthView calendarView = (CalendarMonthView) getParent();
if (calendarView.getParent() instanceof ViewPager) {
ViewGroup parent = (ViewPager) calendarView.getParent();
CalendarCellView tagView = (CalendarCellView) parent.getTag();
if (!isStaticText && tagView != null && tagView.getTag() != null && tagView.getTag() instanceof Long) {
long millis = (long) tagView.getTag();
if (isSameDay(millis, this.millis)) {
// RectF rectF = new RectF(xPos - dp16, getHeight() / 2 - dp16, xPos + dp16, getHeight() / 2 + dp16);
// canvas.drawRoundRect(rectF, RADIUS, RADIUS, mPaintBackground);
}
}
}
if (!isStaticText && isToday(millis)) {
RectF rectF = new RectF(xPos - dp16, getHeight() / 2 - dp16, xPos + dp16, getHeight() / 2 + dp16);
canvas.drawRoundRect(rectF, RADIUS, RADIUS, mPaintBackgroundToday);
}
if (isStaticText) {
// 요일 표시
canvas.drawText(CalendarMonthView.DAY_OF_WEEK[dayOfWeek], xPos, yPos, mPaint);
} else {
// 날짜 표시
if (isToday(millis)) {
canvas.drawText(calendar.get(Calendar.DATE) + "", xPos, yPos, mPaintTextWhite);
} else {
canvas.drawText(calendar.get(Calendar.DATE) + "", xPos, yPos, mPaint);
}
}
if (hasEvent) {
mPaintBackgroundEvent.setColor(getResources().getColor(mColorEvents[0]));
RectF rectF = new RectF(xPos - 5, getHeight() / 2 + 20, xPos + 5, getHeight() / 2 + 30);
canvas.drawRoundRect(rectF, RADIUS, RADIUS, mPaintBackgroundToday);
}
}
private boolean isToday(long millis) {
Calendar cal1 = Calendar.getInstance();
return isSameDay(cal1.getTimeInMillis(), millis);
}
public void setDate(long millis) {
this.millis = millis;
setTag(millis);
}
public void setDayOfWeek(int dayOfWeek) {
this.dayOfWeek = dayOfWeek;
isStaticText = true;
}
public void setEvent(int... resid) {
hasEvent = true;
mColorEvents = resid;
}
public boolean isSameDay(long millis1, long millis2) {
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.setTimeInMillis(millis1);
cal2.setTimeInMillis(millis2);
Log.d("hatti.calendar", "" + cal1.get(Calendar.YEAR) + "" + cal1.get(Calendar.MONTH) + "" + cal1.get(Calendar.DATE) + " VS " +
cal2.get(Calendar.YEAR) + "" + cal2.get(Calendar.MONTH) + "" + cal2.get(Calendar.DATE));
return (cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH) && cal1.get(Calendar.DATE) == cal2.get(Calendar.DATE));
}
public boolean isStaticText() {
return isStaticText;
}
}
Is there anything I should do for add Fragment on Adapter?
in your pager adapter,
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}

How to change the color of the active tab indicator? (Android Studio)

i want to know if i'm able to change the color of the active tab indicator (that light-blue line) to black(#4A4A4A)
Here is the photo
public class PageIndicator extends View {
int totalNoOfDots;
int activeDot;
int dotSpacing;
int horizontalSpace = 5;
Bitmap activeDotBitmap;
Bitmap normalDotBitmap;
int x = 0;
private Paint paint;
public PageIndicator(Context context) {
super(context);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
activeDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_active);
normalDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_normal);
}
public PageIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
activeDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_active);
normalDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_normal);
}
public PageIndicator(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
activeDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_active);
normalDotBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot_normal);
}
#Override
protected void onDraw(Canvas canvas) {
drawDot(canvas);
super.onDraw(canvas);
}
private void drawDot(Canvas canvas) {
for (int i = 0; i < totalNoOfDots; i++) {
if (i == activeDot) {
canvas.drawBitmap(activeDotBitmap, x, 0, paint);
} else {
canvas.drawBitmap(normalDotBitmap, x, 0, paint);
}
x = x + activeDotBitmap.getWidth() + horizontalSpace + dotSpacing;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = totalNoOfDots * (activeDotBitmap.getWidth() + horizontalSpace + getDotSpacing());
width = resolveSize(width, widthMeasureSpec);
int height = activeDotBitmap.getHeight();
height = resolveSize(height, heightMeasureSpec);
setMeasuredDimension(width, height);
}
public void refersh() {
x = 0;
invalidate();
}
public int getTotalNoOfDots() {
return totalNoOfDots;
}
public void setTotalNoOfDots(int totalNoOfDots) {
this.totalNoOfDots = totalNoOfDots;
x = 0;
invalidate();
}
public int getActiveDot() {
return activeDot;
}
public void setActiveDot(int activeDot) {
this.activeDot = activeDot;
x = 0;
invalidate();
}
public int getDotSpacing() {
return dotSpacing;
}
public void setDotSpacing(int dotSpacing) {
this.dotSpacing = dotSpacing;
x = 0;
invalidate();
}
}
if you are using support library.
add this to your tabLayout
app:tabIndicatorColor="#4A4A4A"

Round Custom Progress Bar with segments

I am trying to develop custom progress bar or view, where I can pass in section value and it will create a section in that and then I will fill as per my requirements.
I tired Progress bar with divider but it not in round one ..
Looking for some thing like this
Edit:-
i have edited code as per my need but it not able to do like given image
public class DashedCircularProgress extends RelativeLayout {
public DashedCircularProgress(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public DashedCircularProgress(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
/**
* All the children must have a max height and width, never bigger than the internal circle
*
* #param changed
* #param left
* #param top
* #param right
* #param bottom
*/
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
final int count = getChildCount();
int maxWidth = getWidth() / 2;
int maxHeight = getHeight() / 2;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
int mesaureWidth = child.getMeasuredWidth();
int measureHeight = child.getMeasuredWidth();
ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
child.setTranslationY(padingTop);
RelativeLayout.LayoutParams relativeLayoutParams =
(RelativeLayout.LayoutParams) child.getLayoutParams();
relativeLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
child.setLayoutParams(relativeLayoutParams);
if (mesaureWidth > maxWidth) {
layoutParams.width = maxWidth;
}
if (measureHeight > maxHeight) {
layoutParams.height = maxHeight;
}
}
}
private void init(Context context, AttributeSet attributeSet) {
setWillNotDraw(false);
TypedArray attributes = context.obtainStyledAttributes(attributeSet,
R.styleable.DashedCircularProgress);
initAttributes(attributes);
initPainters();
initValueAnimator();
}
private void initAttributes(TypedArray attributes) {
externalColor = attributes.getColor(R.styleable.DashedCircularProgress_external_color,
externalColor);
internalBaseColor = attributes.getColor(R.styleable.DashedCircularProgress_base_color,
internalBaseColor);
progressColor = attributes.getColor(R.styleable.DashedCircularProgress_progress_color,
progressColor);
max = attributes.getFloat(R.styleable.DashedCircularProgress_max, max);
duration = attributes.getInt(R.styleable.DashedCircularProgress_duration, duration);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
progressPainter.onSizeChanged(h, w);
// externalCirclePainter.onSizeChanged(h, w);
internalCirclePainter.onSizeChanged(h, w);
//iconPainter.onSizeChanged(h, w);
animateValue();
}
private void initPainters() {
progressPainter = new ProgressPainterImp(progressColor, min, max);
//externalCirclePainter = new ExternalCirclePainterImp(externalColor);
internalCirclePainter = new InternalCirclePainterImp(internalBaseColor);
//iconPainter = new IconPainter(image);
}
private void initValueAnimator() {
valueAnimator = new ValueAnimator();
valueAnimator.setInterpolator(interpolator);
valueAnimator.addUpdateListener(new ValueAnimatorListenerImp());
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//externalCirclePainter.draw(canvas);
internalCirclePainter.draw(canvas);
progressPainter.draw(canvas);
//iconPainter.draw(canvas);
invalidate();
}
public void setValue(float value) {
this.value = value;
if (value <= max || value >= min) {
animateValue();
}
}
private void animateValue() {
if (valueAnimator != null) {
valueAnimator.setFloatValues(last, value);
valueAnimator.setDuration(duration);
valueAnimator.start();
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec + heightNormalittation);
}
public void setOnValueChangeListener(OnValueChangeListener valueChangeListener) {
this.valueChangeListener = valueChangeListener;
}
public void setInterpolator(Interpolator interpolator) {
this.interpolator = interpolator;
if (valueAnimator != null) {
valueAnimator.setInterpolator(interpolator);
}
}
public float getMin() {
return min;
}
public void setMin(float min) {
this.min = min;
progressPainter.setMin(min);
}
public float getMax() {
return max;
}
public void setMax(float max) {
this.max = max;
progressPainter.setMax(max);
}
private class ValueAnimatorListenerImp implements ValueAnimator.AnimatorUpdateListener {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Float value = (Float) valueAnimator.getAnimatedValue();
progressPainter.setValue(value);
if (valueChangeListener != null) {
valueChangeListener.onValueChange(value);
}
last = value;
}
}
public interface OnValueChangeListener {
void onValueChange(float value);
}
public void setIcon(int drawable) {
}
public void reset() {
last = min;
}
public int getProgressColor() {
return progressColor;
}
public void setProgressColor(int progressColor) {
this.progressColor = progressColor;
progressPainter.setColor(progressColor);
}
public int getInternalBaseColor() {
return internalBaseColor;
}
public void setInternalBaseColor(int internalBaseColor) {
this.internalBaseColor = internalBaseColor;
internalCirclePainter.setColor(progressColor);
}
public int getExternalColor() {
return externalColor;
}
public void setExternalColor(int externalColor) {
this.externalColor = externalColor;
// externalCirclePainter.setColor(externalColor);
}
public int getDuration() {
return duration;
}
public void setDuration(int duration) {
this.duration = duration;
}
}

Android: apply arbitrary transform to a view

I'd like to take an arbitrary Matrix and apply it to an android.views.View.
The only reliable way I've found is this hack:
MyAnimation animation = new MyAnimation(matrix);
animation.setDuration(0);
animation.setFillAfter(true);
view.setAnimation(animation);
Is there a better way? I tried leveraging getChildStaticTransformation and putting it in a parent, but that wasn't working out (maybe I was doing it wrong?)
In the end, I created my own layout based on AbsoluteLayout, added a Matrix to my LayoutParams, leveraged getChildStaticTransformation, and overrode dispatchTouchEvent in order for my child to respond to the correct bounds when rotated. A lot more difficult than I anticipated.
public class UIViewLayout extends ViewGroup {
#Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
if(child instanceof UIViewLayout) {
t.getMatrix().reset();
UIViewLayout.LayoutParams params = (UIViewLayout.LayoutParams)child.getLayoutParams();
t.setTransformationType(Transformation.TYPE_MATRIX);
t.getMatrix().set(params.matrix);
}
return true;
}
public UIViewLayout(android.content.Context context) {
super(context);
this.setClipChildren(false);
this.setClipToPadding(false);
this.setChildrenDrawingOrderEnabled(true);
this.setStaticTransformationsEnabled(true);
}
public UIViewLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public UIViewLayout(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
int maxHeight = 0;
int maxWidth = 0;
// Find out how big everyone wants to be
measureChildren(widthMeasureSpec, heightMeasureSpec);
// Find rightmost and bottom-most child
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
int childRight;
int childBottom;
UIViewLayout.LayoutParams lp
= (UIViewLayout.LayoutParams) child.getLayoutParams();
childRight = lp.x + child.getMeasuredWidth();
childBottom = lp.y + child.getMeasuredHeight();
maxWidth = Math.max(maxWidth, childRight);
maxHeight = Math.max(maxHeight, childBottom);
}
}
// Account for padding too
//maxWidth += mPaddingLeft + mPaddingRight;
//maxHeight += mPaddingTop + mPaddingBottom;
// Check against minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0),
resolveSizeAndState(maxHeight, heightMeasureSpec, 0));
}
#Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0);
}
#Override
protected void onLayout(boolean changed, int l, int t,
int r, int b) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
UIViewLayout.LayoutParams lp =
(UIViewLayout.LayoutParams) child.getLayoutParams();
int childLeft = lp.x;
int childTop = lp.y;
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(),
childTop + child.getMeasuredHeight());
}
}
}
#Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new UIViewLayout.LayoutParams(getContext(), attrs);
}
// Override to allow type-checking of LayoutParams.
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof UIViewLayout.LayoutParams;
}
#Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
#Override
public boolean shouldDelayChildPressedState() {
return false;
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
for(int i = 0; i < this.getChildCount(); i++) {
View child = getChildAt(i);
if(child instanceof UIViewLayout) {
UIViewLayout.LayoutParams params = (UIViewLayout.LayoutParams)child.getLayoutParams();
if(!params.matrix.isIdentity()) {
MotionEvent ev2 = MotionEvent.obtain(ev);
ev2.setLocation(ev2.getX() - params.x, ev2.getY() - params.y);
Matrix m = new Matrix();
params.matrix.invert(m);
ev2.transform(m);
if(child.dispatchTouchEvent(ev2)) {
return true;
}
ev2.recycle();
}
}
}
return super.dispatchTouchEvent(ev);
}
public static class LayoutParams extends ViewGroup.LayoutParams {
public int x;
public int y;
public Matrix matrix;
public LayoutParams(int width, int height, int x, int y) {
super(width, height);
this.x = x;
this.y = y;
this.matrix = new Matrix();
}
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
}
}

List Item (a view) order changes unexpextedly while (fast) scrolling in a ListView

I am new to android, and ended up (have to) ask a question here,
Let's make it simple, I simply want to make my own TextView-like
(MyView extends View),
this is my code:
public class MyView extends View {
private Paint mPaint;
private String mText;
private Bitmap mBitmap1;
private Bitmap mBitmap2;
public MyView(Context context) {
super(context);
initView();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private final void initView() {
mPaint = new Paint();
}
public void setText(String text) {
mText = text;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredWidth = measureWidth(widthMeasureSpec);
if (mBitmap1 == null) initBitmap1(measuredWidth);
int measuredHeight = measureHeight(heightMeasureSpec);
setMeasuredDimension(measuredWidth, measuredHeight);
}
private void initBitmap1(int measuredWidth) {
mBitmap1 = Bitmap.createBitmap(measuredWidth, Fonts.getHeight(), Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(mBitmap1 );
canvas.drawText(mText, 0, 0, mPaint);
}
private void initBitmap2() {
mBitmap2 = Bitmap.createBitmap(30, Fonts.getHeight(), Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(mBitmap2);
canvas.drawText(mText, 0, 0, mPaint);
}
private int measureWidth(int widthMeasureSpec) {
int measuredWidth = 0;
int specWidthMode = MeasureSpec.getMode(widthMeasureSpec);
int specWidthSize = MeasureSpec.getSize(widthMeasureSpec);
if (specWidthMode == MeasureSpec.EXACTLY) {
measuredWidth = specWidthSize;
} else {
measuredWidth = getWidth();
if (specWidthMode == MeasureSpec.AT_MOST) {
measuredWidth = Math.min(measuredWidth, specWidthSize);
}
}
return measuredWidth;
}
private int measureHeight(int heightMeasureSpec) {
int measuredHeight = 0;
int specHeightMode = MeasureSpec.getMode(heightMeasureSpec);
int specHeightSize = MeasureSpec.getSize(heightMeasureSpec);
if (specHeightMode == MeasureSpec.EXACTLY) {
measuredHeight = specHeightSize;
} else {
measuredHeight = 80;
if (specHeightMode == MeasureSpec.AT_MOST) {
measuredHeight = Math.min(measuredHeight, specHeightSize);
}
}
return measuredHeight;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap1, getLeft(), 0, mPaint);
initBitmap2();
canvas.drawBitmap(mBitmap2, getLeft(), 30, mPaint);
}
}
in my code, i populate some numbers of MyView (let's say 20) in a
ListActivity
my question is why mBitmap1's order changes randomly while i scroll
(up-down) fastly (if i scroll slowly, this problem not occur)..?
mBitmap2 stays where those should be..
you must use a view holder class in order overcome this problem. something like this:
public View getView(final int i, View view, final ViewGroup viewGroup) {
View vi = view;
final ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
vi = inflater.inflate(R.layout.listview_row_cart, null);
holder.yourbutton = (Button) vi.findViewById(R.id.btn);
vi.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.yourbutton.setText("Start");
}
class ViewHolder {
Button yourbutton
}

Categories

Resources