I have a problem that all of the customize progress didn't show progress in a ListView.
Here is mucustomize progress view below:
public class LProgressBar extends View {
private final int DEFAULT_HEIGHT = dp2px(10);
private static final int DEFAULT_REACHED_COLOR = 0xFFE66059;
private static final int DEFAULT_UNREACHED_COLOR = 0xFF7A9B5B;
private static final int DEFAULT_ANIMATE_DURATION = 1000;
private static final int DEFAULT_MAX_VALUE = 100;
private static final int DEFAULT_PROGRESS = 0;
private static final Boolean DEBUG = false;
private int mHeight;
private int mRealWidth;
private int mReachedColor;
private int mUnreachedColor;
private int mDuration;
private float mProgress;
private int mMaxValue;
private boolean debug;
private Paint mUnreachedPaint;
private Paint mReachedPaint;
public LProgressBar(Context context) {
this(context, null);
}
public LProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
obtainStyledAttributes(attrs);
reset();
}
private void obtainStyledAttributes(AttributeSet attrs) {
final TypedArray attr = getContext().obtainStyledAttributes(attrs, R.styleable.LProgressBar);
mHeight = (int) attr.getDimension(R.styleable.LProgressBar_ruman_height, DEFAULT_HEIGHT);
mReachedColor = attr.getColor(R.styleable.LProgressBar_ruman_reached_color, DEFAULT_REACHED_COLOR);
mUnreachedColor = attr.getColor(R.styleable.LProgressBar_ruman_unreached_color, DEFAULT_UNREACHED_COLOR);
debug = attr.getBoolean(R.styleable.LProgressBar_ruman_debug, DEBUG);
mDuration = (int) attr.getDimension(R.styleable.LProgressBar_ruman_duration, DEFAULT_ANIMATE_DURATION);
mProgress = (float) attr.getFloat(R.styleable.LProgressBar_ruman_progress, DEFAULT_PROGRESS);
mMaxValue = (int) attr.getDimension(R.styleable.LProgressBar_ruman_maxvalue, DEFAULT_MAX_VALUE);
attr.recycle();
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
width = 100;
if (widthMode == MeasureSpec.AT_MOST)
width = Math.min(widthSize, 100);
}
if (heightMode == MeasureSpec.EXACTLY)
height = heightSize;
else {
height = mHeight;
if (heightMode == MeasureSpec.AT_MOST)
height = Math.min(heightSize, mHeight);
}
setMeasuredDimension(width, height);
mRealWidth = getMeasuredWidth();
}
#Override
protected synchronized void onDraw(Canvas canvas) {
canvas.drawLine(0, 0, mRealWidth, 0, mUnreachedPaint);
canvas.drawLine(0, 0, mProgress, 0, mReachedPaint);
}
private void reset() {
initUnreachedPaint();
initReachedPaint();
}
private void initUnreachedPaint() {
mUnreachedPaint = new Paint();
mUnreachedPaint.setColor(mUnreachedColor);
mUnreachedPaint.setStrokeWidth(dp2px(mHeight));
}
private void initReachedPaint() {
mReachedPaint = new Paint();
mReachedPaint.setColor(mReachedColor);
mReachedPaint.setStrokeWidth(dp2px(mHeight));
}
public synchronized void setProgress(float progress) {
float radio = (float) progress * 1.0f / mMaxValue * 1.0f;
mProgress = (float) mRealWidth * radio * 1.0f;
invalidate();
}
private void startProgressAnim() {
ValueAnimator animator = ValueAnimator.ofFloat(0, mProgress);
animator.setDuration(mDuration);
animator.setInterpolator(new DecelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
mProgress = value;
invalidate();
}
});
animator.start();
}
/**
* dp2px
*
* #param dpValue dp
* #return px
*/
private int dp2px(int dpValue) {
return (int) getContext().getResources().getDisplayMetrics().density * dpValue;
}
}
I put it in a ListView and i called lProgressBar.setProgress(50.0f); but not working, all of the progress is 0. I tried call notifyDataSetChanged() still not working. Help me plz.
Related
I have implemented a custom view which looks like a seekbar with drawable attached at end Custom Score bar. I have provided methods to change colour for progress, change width of the progress(along with the rocket icon), and change the icon itself(for different colours).
public class RocketView extends View {
private int mProgressWidth = 12;
private Drawable mIndicatorIcon;
private int mProgress, mMin = 0, mMax = 100;
private Paint mBackgroundPaint, mProgressPaint;
private RectF mBackgroundRect = new RectF();
private RectF mProgressRect = new RectF();
private int mIndicatorSize;
private int mProgressColor;
private int mIndicatorLeft;
public RocketView(Context context) {
super(context);
init(context, null);
}
public RocketView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
void init(Context context, AttributeSet attrs) {
float density = getResources().getDisplayMetrics().density;
int backgroundColor = ContextCompat.getColor(context, R.color.color_bg);
int progressColor = ContextCompat.getColor(context, R.color.color_progress);
mProgressWidth = (int) (mProgressWidth * density);
mIndicatorIcon = ContextCompat.getDrawable(context, R.drawable.rocket_15);
if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RocketView, 0, 0);
Drawable indicatorIcon = a.getDrawable(R.styleable.RocketView_indicatorIcon);
if (indicatorIcon != null) mIndicatorIcon = indicatorIcon;
mProgress = a.getInteger(R.styleable.RocketView_progress, 0);
mProgressWidth = (int) a.getDimension(R.styleable.RocketView_thickness, mProgressWidth);
mIndicatorSize = 10*mProgressWidth;
mIndicatorIcon.setBounds(0, 0, mIndicatorSize, mIndicatorSize);
mProgressColor = a.getColor(R.styleable.RocketView_progressColor, progressColor);
backgroundColor = a.getColor(R.styleable.RocketView_backgroundColor, backgroundColor);
a.recycle();
}
// range check
mProgress = (mProgress > mMax) ? mMax : mProgress;
mProgress = (mProgress < mMin) ? mMin : mProgress;
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(backgroundColor);
mBackgroundPaint.setAntiAlias(true);
mBackgroundPaint.setStyle(Paint.Style.STROKE);
mBackgroundPaint.setStrokeWidth(mProgressWidth);
mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
mProgressPaint = new Paint();
mProgressPaint.setColor(mProgressColor);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mProgressPaint.setStrokeWidth(mProgressWidth);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
int top = 0;
int left = 0;
//normalizing the value from 0 to 100 to 0 to container width
/* Formula for linear range [A..B] to [C..D],
*
* (D-C)*(X-A)
X' = ----------- + C
(B-A)
*/
int extraOffset = dpToPx(2);
int extraPadding = dpToPx(8);
int x = (width - left)*(mProgress - 0)/(100 -0) + 0;
top = 2*mIndicatorSize/5 + mProgressWidth/2 +extraOffset;
mBackgroundRect.set(left +extraPadding, top, left + width -extraPadding, top+mProgressWidth/2 );
int indicatorLeft = width - (left + x);
if (indicatorLeft < mIndicatorSize) {
mIndicatorLeft = width - mIndicatorSize;
mProgressRect.set(left +extraPadding, top, left + x - dpToPx(20), top + mProgressWidth/2 );
}
else {
mIndicatorLeft = left + x - dpToPx(16);
mProgressRect.set(left +extraPadding, top, left + x, top + mProgressWidth/2);
}
setMeasuredDimension(width, mIndicatorSize);
}
#Override
protected void onDraw(Canvas canvas) {
// draw the background
canvas.drawRoundRect(mBackgroundRect, mProgressWidth/2, mProgressWidth/2, mBackgroundPaint);
//draw progress
canvas.drawRoundRect(mProgressRect, mProgressWidth/2, mProgressWidth/2, mProgressPaint);
// draw the indicator icon
canvas.translate(mIndicatorLeft,0);
mIndicatorIcon.draw(canvas);
}
public static int dpToPx(int dp){
return dp * (Resources.getSystem().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
public void setIndicatorIcon(int indicatorIcon) {
mIndicatorIcon = getResources().getDrawable(indicatorIcon);
invalidate();
}
public void setProgress(int progress) {
mProgress = progress;
invalidate();
}
public void setProgressColor(int color) {
mProgressColor = color;
mProgressPaint = new Paint();
mProgressPaint.setColor(mProgressColor);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mProgressPaint.setStrokeWidth(mProgressWidth);
invalidate();
}
}
now i am instantiating it in activity as:
RocketView rv = (RocketView) findViewById(R.id.rv);
rv.setProgressColor(getResources().getColor(R.color.colorAccent));
rv.setProgress(100);
rv.setIndicatorIcon(R.drawable.rocket_15);
If I don't set indicator icon in activity the icon is shown but as soon as I call the method setIndicatorIcon() the icon disappears. What am I missing?
Im using a ViewPager to show Images. The ViewPager is working correctly but there is an error with the indicator. When i swipe to the very last entry the indicator is only at round about 70% of the way. See the screen:
That is the problem. I dont know if the indicator is just too small, moving to slow or there are another hidden entries in the viewpager but since i cant swipe any further to the right i guess there is a bug with the indicator size or moving or something like that.
This is how i initializ my viewpager:
this.viewPager.setId(R.id.image_inspiration_pager);
this.viewPager.setClipToPadding(false);
this.viewPager.setPadding(0, 0, ((int) HelperPixel.convertDpToPixel(this.getContext(), 48)), 0);
this.viewPager.setAdapter(adapter);
this.viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
private static final float thresholdOffset = 0.5f;
private boolean scrollStarted = false;
private boolean checkDirection = false;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (position == 0) {
viewPager.setPadding(0, 0, ((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0);
return;
} else if (position == (adapter.getCount() - 1)) {
viewPager.setPadding(((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0, 0, 0);
return;
}
if (this.checkDirection) {
if (thresholdOffset > positionOffset) {
viewPager.setPadding(0, 0, ((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0);
} else {
viewPager.setPadding(((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0, 0, 0);
}
this.checkDirection = false;
}
}
#Override
public void onPageSelected(int position) {}
#Override
public void onPageScrollStateChanged(int state) {
if (!this.scrollStarted && state == ViewPager.SCROLL_STATE_DRAGGING) {
this.scrollStarted = true;
this.checkDirection = true;
} else {
this.scrollStarted = false;
}
}
});
Implementation of TabLayout:
public class TabsSlidingLayout extends HorizontalScrollView {
private static final int TITLE_OFFSET_DIPS = 24;
private static final int TAB_VIEW_PADDING_DIPS = 16;
private static final int TAB_VIEW_TEXT_SIZE_SP = 14;
private int titleOffset;
private int tabViewLayoutId;
private int tabViewTextViewId;
private ViewPager viewPager;
private ViewPager.OnPageChangeListener pageChangeListener;
private final TabsSlidingStrip tabStrip;
public TabsSlidingLayout(Context context) {
this(context, null);
}
public TabsSlidingLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TabsSlidingLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setHorizontalScrollBarEnabled(false);
this.setFillViewport(true);
this.titleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
this.tabStrip = new TabsSlidingStrip(context);
this.addView(this.tabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
public void setCustomBackgroundColor(int color) {
this.tabStrip.setBackgroundColor(color);
}
public void setCustomTabColorizer(TabColorizer tabColorizer) {
this.tabStrip.setCustomTabColorizer(tabColorizer);
}
public void setSelectedIndicatorColors(int... colors) {
this.tabStrip.setSelectedIndicatorColors(colors);
}
public void setDividerColors(int... colors) {
this.tabStrip.setDividerColors(colors);
}
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
this.pageChangeListener = listener;
}
public void setCustomTabView(int layoutResId, int textViewId) {
this.tabViewLayoutId = layoutResId;
this.tabViewTextViewId = textViewId;
}
public void setViewPager(ViewPager viewPager) {
this.tabStrip.removeAllViews();
this.viewPager = viewPager;
if (this.viewPager != null) {
this.viewPager.addOnPageChangeListener(new InternalViewPagerListener());
this.populateTabStrip();
}
}
protected TextView createDefaultTabView(Context context) {
TextView textView = new TextView(context);
textView.setGravity(Gravity.CENTER);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
textView.setTypeface(Typeface.DEFAULT_BOLD);
textView.setTextColor(ContextCompat.getColor(context, R.color.white));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
TypedValue outValue = new TypedValue();
this.getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
textView.setBackgroundResource(outValue.resourceId);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
textView.setAllCaps(true);
}
int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
textView.setPadding(padding, padding, padding, padding);
return textView;
}
private void populateTabStrip() {
final PagerAdapter adapter = this.viewPager.getAdapter();
final View.OnClickListener tabClickListener = new TabClickListener();
for (int i = 0; i < adapter.getCount(); i++) {
View tabView = null;
TextView tabTitleView = null;
if (this.tabViewLayoutId != 0) {
tabView = LayoutInflater.from(this.getContext()).inflate(this.tabViewLayoutId, this.tabStrip, false);
tabTitleView = (TextView) tabView.findViewById(this.tabViewTextViewId);
}
if (tabView == null) {
tabView = createDefaultTabView(this.getContext());
}
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
tabTitleView = (TextView) tabView;
}
tabTitleView.setText(adapter.getPageTitle(i));
tabView.setOnClickListener(tabClickListener);
this.tabStrip.addView(tabView);
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (this.viewPager != null) {
this.scrollToTab(this.viewPager.getCurrentItem(), 0);
}
}
private void scrollToTab(int tabIndex, int positionOffset) {
final int tabStripChildCount = this.tabStrip.getChildCount();
if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
return;
}
View selectedChild = this.tabStrip.getChildAt(tabIndex);
if (selectedChild != null) {
int targetScrollX = selectedChild.getLeft() + positionOffset;
if (tabIndex > 0 || positionOffset > 0) {
targetScrollX -= this.titleOffset;
}
this.scrollTo(targetScrollX, 0);
}
}
public interface TabColorizer {
int getIndicatorColor(int position);
int getDividerColor(int position);
}
private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
private int scrollState = -1;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
int tabStripChildCount = tabStrip.getChildCount();
if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
return;
}
tabStrip.onViewPagerPageChanged(position, positionOffset);
View selectedTitle = tabStrip.getChildAt(position);
int extraOffset = (selectedTitle != null) ? (int) (positionOffset * selectedTitle.getWidth()) : 0;
scrollToTab(position, extraOffset);
if (pageChangeListener != null) {
pageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
#Override
public void onPageScrollStateChanged(int state) {
this.scrollState = state;
if (pageChangeListener != null) {
pageChangeListener.onPageScrollStateChanged(state);
}
}
#Override
public void onPageSelected(int position) {
if (this.scrollState == ViewPager.SCROLL_STATE_IDLE) {
tabStrip.onViewPagerPageChanged(position, 0f);
scrollToTab(position, 0);
}
if (pageChangeListener != null) {
pageChangeListener.onPageSelected(position);
}
}
}
private class TabClickListener implements View.OnClickListener {
#Override
public void onClick(View view) {
for (int i = 0; i < tabStrip.getChildCount(); i++) {
if (view == tabStrip.getChildAt(i)) {
viewPager.setCurrentItem(i);
return;
}
}
}
}
}
TabSlidingStrip implementation:
class TabsSlidingStrip extends LinearLayout {
private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 0;
private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 2;
private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFFFFFFFF;
private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 0;
private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
private static final float DEFAULT_DIVIDER_HEIGHT = 0.0f;
private final int bottomBorderThickness;
private final Paint bottomBorderPaint;
private final int selectedIndicatorThickness;
private final Paint selectedIndicatorPaint;
private final Paint dividerPaint;
private final float dividerHeight;
private int selectedPosition;
private float selectionOffset;
private TabsSlidingLayout.TabColorizer customTabColorizer;
private final SimpleTabColorizer defaultTabColorizer;
public TabsSlidingStrip(Context context) {
this(context, null);
}
public TabsSlidingStrip(Context context, AttributeSet attrs) {
super(context, attrs);
this.setWillNotDraw(false);
final float density = getResources().getDisplayMetrics().density;
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true);
final int themeForegroundColor = outValue.data;
this.setBackgroundColor(ContextCompat.getColor(context, R.color.primaryColor));
this.defaultTabColorizer = new SimpleTabColorizer();
this.defaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
this.defaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor, DEFAULT_DIVIDER_COLOR_ALPHA));
this.bottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
this.bottomBorderPaint = new Paint();
this.bottomBorderPaint.setColor(setColorAlpha(themeForegroundColor, DEFAULT_BOTTOM_BORDER_COLOR_ALPHA));
this.selectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
this.selectedIndicatorPaint = new Paint();
this.dividerHeight = DEFAULT_DIVIDER_HEIGHT;
this.dividerPaint = new Paint();
this.dividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
}
void setCustomTabColorizer(TabsSlidingLayout.TabColorizer customTabColorizer) {
this.customTabColorizer = customTabColorizer;
this.invalidate();
}
void setSelectedIndicatorColors(int... colors) {
this.customTabColorizer = null;
this.defaultTabColorizer.setIndicatorColors(colors);
this.invalidate();
}
void setDividerColors(int... colors) {
this.customTabColorizer = null;
this.defaultTabColorizer.setDividerColors(colors);
this.invalidate();
}
void onViewPagerPageChanged(int position, float positionOffset) {
this.selectedPosition = position;
this.selectionOffset = positionOffset;
this.invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
final int height = this.getHeight();
final int childCount = this.getChildCount();
final int dividerHeightPx = (int) (Math.min(Math.max(0f, this.dividerHeight), 1f) * height);
final TabsSlidingLayout.TabColorizer tabColorizer = this.customTabColorizer != null ? this.customTabColorizer : this.defaultTabColorizer;
if (childCount > 0) {
View selectedTitle = getChildAt(this.selectedPosition);
int left = selectedTitle.getLeft();
int right = selectedTitle.getRight();
int color = tabColorizer.getIndicatorColor(this.selectedPosition);
if (this.selectionOffset > 0f && this.selectedPosition < (getChildCount() - 1)) {
int nextColor = tabColorizer.getIndicatorColor(this.selectedPosition + 1);
if (color != nextColor) {
color = blendColors(nextColor, color, this.selectionOffset);
}
View nextTitle = getChildAt(this.selectedPosition + 1);
left = (int) (this.selectionOffset * nextTitle.getLeft() + (1.0f - this.selectionOffset) * left);
right = (int) (this.selectionOffset * nextTitle.getRight() + (1.0f - this.selectionOffset) * right);
}
this.selectedIndicatorPaint.setColor(color);
canvas.drawRect(left, height - this.selectedIndicatorThickness, right, height, this.selectedIndicatorPaint);
}
canvas.drawRect(0, height - this.bottomBorderThickness, this.getWidth(), height, this.bottomBorderPaint);
int separatorTop = (height - dividerHeightPx) / 2;
for (int i = 0; i < childCount - 1; i++) {
View child = getChildAt(i);
this.dividerPaint.setColor(tabColorizer.getDividerColor(i));
canvas.drawLine(child.getRight(), separatorTop, child.getRight(), separatorTop + dividerHeightPx, this.dividerPaint);
}
}
private static int setColorAlpha(int color, byte alpha) {
return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
}
private static int blendColors(int color1, int color2, float ratio) {
final float inverseRation = 1f - ratio;
float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
return Color.rgb((int) r, (int) g, (int) b);
}
private static class SimpleTabColorizer implements TabsSlidingLayout.TabColorizer {
private int[] indicatorColors;
private int[] dividerColors;
#Override
public final int getIndicatorColor(int position) {
return this.indicatorColors[position % this.indicatorColors.length];
}
void setIndicatorColors(int... colors) {
this.indicatorColors = colors;
}
#Override
public final int getDividerColor(int position) {
return this.dividerColors[position % this.dividerColors.length];
}
void setDividerColors(int... colors) {
this.dividerColors = colors;
}
}
}
The first screenshot is from a tablet. Here is a screen from my smartphone:
As you can see for the smartphone the gap is much smaller than on the tablet.
Any idea what could be the problem?
Add the following code to the bottom of createDefaultTabView:
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
textView.setWidth(size.x / this.viewPager.getAdapter().getCount());
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;
}
}
I have a customview , inside it , i have one view slide up and down , when slide i draw fade background like this :
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.drawARGB(alpha, 0, 0, 0);
super.dispatchDraw(canvas);
}
It work with my device android 4.2.2 but with android 4.4.2 or google nexus one android 2.3.7 ,it so bad.
2 images below show in my device 4.2.2(slide in and slide out):
http://imgur.com/p6i9gw8
http://imgur.com/9Sdzy7v
and 2 images below show in google nexus one android 2.3.7(slide in and slide out):
http://imgur.com/ZGKiRJi
http://imgur.com/Uf3vRdb
As you can see, in 2 image first, fade draw correct , and in other, it look bad.
Complete code for this view is :
public class SlideView extends ViewGroup {
private static final int MAXDURATIONSLIDE = 500;
protected View content;
private int childHeight;
private int childOffset;
private int childWidth;
private int alpha;
private Fillinger fillinger;
public ISlide getSlideChangeListener() {
return slideListener;
}
public void setSlideChangeListener(ISlide slideChangeListener) {
this.slideListener = slideChangeListener;
}
private ISlide slideListener;
public SlideView(Context context) {
super(context);
init(context, null);
}
private void init(Context context, AttributeSet attrs) {
if(attrs!=null){
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlideView);
try {
int contentLayoutId = a.getResourceId(R.styleable.SlideView_slideView, 0);
DebugLog.d(contentLayoutId);
setContent(contentLayoutId);
} finally {
a.recycle();
}
}
fillinger = new Fillinger(context);
}
public SlideView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context,attrs);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = r - l;
final int height = b - t;
DebugLog.d("width "+width+" height "+height);
childOffset = height;
content.layout(0, childOffset, childWidth, childOffset + childHeight);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(0, widthMeasureSpec);
int height = getDefaultSize(0, heightMeasureSpec);
measureChild(content, widthMeasureSpec, height);
childHeight = content.getMeasuredHeight();
childWidth = content.getMeasuredWidth();
DebugLog.d("childWidth "+childWidth+" childHeight "+childHeight);
setMeasuredDimension(width, height);
}
public void setContent(int resId) {
View view = LayoutInflater.from(getContext()).inflate(resId, this,false);
setContent(view);
}
public void setContent(View v) {
if (content != null)
removeView(content);
content = v;
addView(content);
}
private void moveViewByY(int diffY) {
childOffset += diffY;
alpha = (int) (Math.abs((getHeight()-childOffset)*255/(childHeight))*0.5f);
content.layout(0, childOffset, childWidth, childOffset + childHeight);
if(slideListener!=null){
slideListener.onSlide(childOffset,childHeight);
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.drawARGB(alpha, 0, 0, 0);
super.dispatchDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(isIn()&&touchOutSide(event)){
toogle();
return true;
}
return false;
}
private boolean touchOutSide(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
if(x<content.getLeft()||x>content.getRight()||y<content.getTop()||y>content.getBottom()){
return true;
}
return false;
}
public void hide(){
if(isIn()){
fillinger.startScroll(content.getTop(),getHeight(),childHeight,MAXDURATIONSLIDE);
}
}
public void show(){
if(!isIn()){
fillinger.startScroll(content.getTop(),getHeight()-childHeight,childHeight,MAXDURATIONSLIDE);
}
}
public void toogle(){
fillinger.cancleAnimation();
if(isIn()){
hide();
}else{
show();
}
}
public boolean isIn(){
return content.getTop()<getHeight();
}
public class Fillinger implements Runnable {
private static final String tag = "Fillinger";
private Scroller mScroller;
private int lastY;
private boolean more;
private int currentY;
private int diffY;
public Fillinger(Context context) {
mScroller = new Scroller(context);
}
public void startScroll(float startY, float endY, float maxDistance, int maxDurationForFling) {
int duration = (int) Math.min(Math.abs((endY - startY)) / maxDistance * maxDurationForFling, maxDurationForFling);
lastY = (int) startY;
if(slideListener!=null){
slideListener.onStartSlide();
}
mScroller.startScroll(0, (int) startY, 0, -(int) (endY - startY), duration);
setDrawingCacheEnabled(true);
post(this);
}
public void cancleAnimation(){
removeCallbacks(this);
}
#Override
public void run() {
more = mScroller.computeScrollOffset();
currentY = mScroller.getCurrY();
diffY = lastY - currentY;
moveViewByY(diffY);
lastY = currentY;
if (more) {
post(this);
}else{
setDrawingCacheEnabled(false);
if(slideListener!=null){
slideListener.onSlideFinish(isIn());
}
}
}
}
}
What i missing?
Sorry for my bad english.
Thanks all.
Edit: finally , i must call invalidate in moveViewByY method like this
private void moveViewByY(int diffY) {
childOffset += diffY;
alpha = (int) (Math.abs((getHeight()-childOffset)*255/(childHeight))*0.5f);
content.layout(0, childOffset, childWidth, childOffset + childHeight);
invalidate();
if(slideListener!=null){
slideListener.onSlide(childOffset,childHeight);
}
}
I dont know why , may be invalidate , view tree redraw and old canvas cleared.
Expect best solution, thanks .
am looking to create a customs slider component with the functionality of s seek bar.
I have been following this tutorial
http://www.androidenea.com/2011/10/creating-custom-view-part-1-graphics.html
however, I wish to use my own graphics which aren't .9.png graphics. I also need to resize the seek bar and the slider.
If anyone can help on this I'd greatly appreciate it. I have it to a stage where I have it resized and the graphics are changed however, when I use my finger to slide upwards I need to slide to the top of the screen in order for my seebar to reach the top of the frame.
Please any help is appreciated, this is what I've implemented so far:
package com.enea.training.customview;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class CustomSlider extends View {
interface CustomSliderPositionListener {
void onPositionChange(float newPosition);
}
private final Drawable mIndicator;
private final Drawable mBackground;
private float mMin;
private float mMax;
private float mPosition;
private Rect mViewRect;
private int mIndicatorOffset;
private int mIndicatorMaxPos;
private int mIndicatorMinPos;
private CustomSliderPositionListener mPositionListener;
private boolean mIsVertical;
public CustomSlider(final Context context) {
this(context, null, 0);
}
public CustomSlider(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomSlider(final Context context, final AttributeSet attrs,
final int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CustomSlider);
final int vertical = a.getInt(R.styleable.CustomSlider_orientation, 0);
mIsVertical = (vertical != 0);
final float max = a.getFloat(R.styleable.CustomSlider_max, 1.0f);
final float min = a.getFloat(R.styleable.CustomSlider_min, -1.0f);
setMinMax(min, max);
final Resources res = context.getResources();
if (mIsVertical) {
mIndicator = res.getDrawable(R.drawable.beer_with_arrows);
mBackground = res.getDrawable(R.drawable.glass);
} else {
mIndicator = res.getDrawable(R.drawable.indicator_horizontal);
mBackground = res.getDrawable(R.drawable.background_horizontal);
}
mPosition =(mMax - 1) ;/// 2 + mMin;
mPositionListener = null;
setOnTouchListener(new OnTouchListener() {
public boolean onTouch(final View v, final MotionEvent event) {
final float pos;
if (mIsVertical) {
float divisor = mIndicatorMinPos-mIndicatorMaxPos;
pos = (mMax - ((mMax - mMin) / divisor)
* event.getY());
} else {
pos = (mMin + ((mMax - mMin) / (mIndicatorMaxPos - mIndicatorMinPos))
* event.getX());
}
setPosition(pos);
return true;
}
});
}
#Override
protected void onDraw(final Canvas canvas) {
if (mViewRect == null) {
mViewRect = new Rect();
mViewRect.set(20,20,20,20);
getDrawingRect(mViewRect);
if (mIsVertical) {
mIndicatorOffset = mIndicator.getIntrinsicHeight();
mIndicatorMaxPos = mViewRect.top + mIndicatorOffset;
mIndicatorMinPos = mViewRect.bottom - mIndicatorOffset;
} else {
mIndicatorOffset = mIndicator.getIntrinsicWidth();
mIndicatorMaxPos = mViewRect.right - mIndicatorOffset;
mIndicatorMinPos = mViewRect.left + mIndicatorOffset;
}
mBackground.setBounds(mViewRect.left, mViewRect.top, mViewRect.right,
mViewRect.bottom);
}
final float pos;
final int left;
final int right;
final int top;
final int bottom;
if (mIsVertical) {
pos = mIndicatorMaxPos
+ ((mIndicatorMinPos - mIndicatorMaxPos) / (mMax - mMin))
* (mMax - mPosition);
left = mViewRect.centerX() - (mIndicator.getIntrinsicWidth() / 2);
top = (int) pos - (mBackground.getIntrinsicHeight() / 2);
} else {
pos = mIndicatorMinPos
+ ((mIndicatorMaxPos - mIndicatorMinPos) / (mMax - mMin))
* (mPosition - mMin);
left = (int) pos - (mIndicator.getIntrinsicWidth() / 2);
top = mViewRect.centerY() - (mIndicator.getIntrinsicHeight() / 2);
}
right = left + mIndicator.getIntrinsicWidth();
bottom = top + mIndicator.getIntrinsicHeight();
mIndicator.setBounds(left, top, right, bottom);
mIndicator.draw(canvas);
mBackground.draw(canvas);
}
#Override
protected void onMeasure(final int widthMeasureSpec,
final int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mIsVertical) {
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;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
//setMeasuredDimension(getSuggestedMinimumWidth(),getSuggestedMinimumHeight());
// setMeasuredDimension(mIndicator.getIntrinsicWidth(), getMeasuredHeight());
} else {
setMeasuredDimension(getMeasuredWidth(), mBackground.getIntrinsicHeight());
}
}
public float getMin() {
return mMin;
}
public float getMax() {
return mMax;
}
public float getPosition() {
return mPosition;
}
public void setPosition(float position) {
position = within(position, mMin, mMax);
if (position != mPosition) {
mPosition = position;
invalidate();
if (mPositionListener != null) {
mPositionListener.onPositionChange(mPosition);
}
}
}
private static float within(float position, final float min, final float max) {
if (position < min) {
position = min;
}
if (position > max) {
position = max;
}
return position;
}
public void setMinMax(final float min, final float max) {
if ((min != mMin) || (max != mMax)) {
if (min > max) {
throw new IllegalArgumentException(
"setMinMax: min must be smaller than max.");
}
mMin = min;
mMax = max;
setPosition(mPosition);
invalidate();
}
}
public void setPositionListener(final CustomSliderPositionListener listener) {
mPositionListener = listener;
}
}
****EDIT****
So below I have done up a rough pic to show what I'm trying to do. So my custom view includes the slider, and frame (background and indicator). The slider (indicator) is dragged by user up and down inside the red background..
I would apprecaite any help and thank you for your help so far...
I