onDraw method is not drawing - android

i am working on application in which my ondraw method is not working properly. I checked similar questions but i didnt get the what is the problem. This code drawing a square but not the correct size. It's so small. Also ı write a code for cells but they are not even working. I didnt get the where is the problem.
My class Code:
public SudokuBoard(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
setWillNotCacheDrawing(false);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.SudokuBoard,0,0);
try{
boardColor = a.getInteger(R.styleable.SudokuBoard_boardColor,0);
}
finally {
a.recycle();
}
}
#Override
protected void onMeasure(int width, int height){
super.onMeasure(getWidth(),getHeight());
int dimension = Math.min(this.getMeasuredWidth(),this.getMeasuredHeight());
cellSize = dimension/9;
setMeasuredDimension(dimension,dimension);
}
#Override
protected void onDraw(Canvas canvas){
boardColorPaint.setStyle(Paint.Style.STROKE);
boardColorPaint.setStrokeWidth(16);
boardColorPaint.setColor(boardColor);
boardColorPaint.setAntiAlias(true);
canvas.drawRect(0,0,getWidth(),getHeight(),boardColorPaint);
drawBoard(canvas);
}
private void drawThinLine(){
boardColorPaint.setStyle(Paint.Style.STROKE);
boardColorPaint.setStrokeWidth(10);
boardColorPaint.setColor(boardColor);
}
private void drawThickLine(){
boardColorPaint.setStyle(Paint.Style.STROKE);
boardColorPaint.setStrokeWidth(4);
boardColorPaint.setColor(boardColor);
}
private void drawBoard(Canvas canvas){
for(int c = 0;c<10;c++){
if(c%3==0){
drawThickLine();
}
else{
drawThinLine();
}
canvas.drawLine(cellSize*c,0,cellSize*c,getWidth(),boardColorPaint);
}
for(int r = 0;r<10;r++){
if(r%3==0){
drawThickLine();
}
else{
drawThinLine();
}
canvas.drawLine(0,cellSize*r,getWidth(),cellSize*r,boardColorPaint);
}
}

You cannot call getMeasuredWidth() or getMeasuredHeight() from within onMeasure(), those values aren't determined until setMeasuredDimension() is called.
Also you shouldn't call super.onMeasure(), your job in onMeasure() is to calculate the dimensions and call setMeasuredDimension().
Assuming your SodukoBoard is set as layout_width="match_parent" and layout_height="match_parent", this code should set your SodukoBoard width to a square using the lesser of the two dimensions:
void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
int dimension = Math.min(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
setMeasuredDimension (dimension, dimension);
}

Related

Android fragmented ProgressBar (like defrag or bittorrent)

I need an advise on optimizing a custom indicator, that shows progress of downloading file in multiple chunks, in concurrent threads. I couldn't find a correct name for that type - pieces, fragments, chunks? But it should look like bittorrent progress bar or defrag progress from Win XP. And it looks like this:
My custom ProgressBar class as following:
public class FragmentedProgressBar extends ProgressBar {
private int height;
private float fragWidth;
private final ArrayList<Integer> stateColors = new ArrayList<>();
private final Paint progressPaint = new Paint();
private ConcurrentHashMap<Integer, Integer> barData;
public FragmentedProgressBar(Context context) {
super(context);
this.init(context);
}
public FragmentedProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
this.init(context);
}
public FragmentedProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.init(context);
}
#SuppressWarnings("deprecation")
private void init(Context context) {
barData = new ConcurrentHashMap<>();
stateColors.addAll(
Arrays.asList(
context.getResources().getColor(android.R.color.holo_blue_dark),
context.getResources().getColor(android.R.color.holo_green_light),
context.getResources().getColor(android.R.color.holo_orange_light),
context.getResources().getColor(android.R.color.holo_red_light)
)
);
}
public synchronized void setProgress(int progress, int state) {
/* state serves to indicate "started", "ready", "retry", "error" by color */
if(barData != null ) {
barData.put(progress, state);
}
super.setProgress(progress);
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
height = getMeasuredHeight();
setMeasuredDimension(width, height);
fragWidth = (float) width / getMax();
}
#Override
protected synchronized void onDraw(Canvas canvas) {
for (Map.Entry<Integer, Integer> ent : barData.entrySet()) {
int id = ent.getKey();
int state = ent.getValue();
float xleft = fragWidth * ( id - 1 );
progressPaint.setColor(stateColors.get(state));
canvas.drawRect(xleft, 0.0f, xleft + fragWidth, 0.0f + height, progressPaint);
}
}
}
However, in this approach, it redraws whole bar on every progress tick, and, I think, it's quite inefficient.
I've done formerly same bar in javafx, extending Canvas and drawing each chunk separately on it.
What will be a better solution for android, desirably extending and reusing the ProgressBar class?
Thanks

Android Setting GridView Height

I have a GridView with variable height cells. I want the row to be as high as all the largest cell in the row. I am able to adjust the cell heights to be consistent on a row, but I cannot set the Height of the GridView and have it actually change.
Another problem is that this GridView is in a ScrollView, so having a scroll bar is out of the question.
This is a problem because the way the GridView determines the height of the entire Grid is to take the first cell and multiply it by the number of rows. This is an obvious problem if the rows can have different heights. For example:
I have tried numerous ways to update it, but I am sure I am missing something simple. I am trying to do the update in a ViewTreeObserver so I know that the GridView has rendered so my calcs are correct (and they are). The code:
ViewTreeObserver treeListener = mGridView.getViewTreeObserver();
treeListener.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
mGridView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
else {
mGridView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
// Calculate the new height we want for the GridView
int newHeight = determineCellHeight(mGridView, mNumberOfColumns, mRows);
ViewGroup.LayoutParams params = mGridView.getLayoutParams();
params.height = newHeight;
mGridView.setLayoutParams(params);
// Have tried all of these too!!!
// mAdapter.notifyDataSetChanged();
// mGridView.requestLayout();
// mGridView.invalidateViews();
// mGridView.refreshDrawableState();
// mGridView.setLayoutParams(new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, newHeight + 10));
// mGridView.setLayoutParams(new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, newHeight + 10));
// View lastChild = mGridView.getChildAt( mGridView.getChildCount() - 1 );
// mGridView.setLayoutParams( new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, lastChild.getBottom() ) );
// mAdapter.notifyDataSetChanged();
// mGridView.invalidateViews();
// mGridView.setMinimumHeight(newHeight);
// mGridView.requestLayout();
// mGridView.refreshDrawableState();
}
});
I am beginning to wonder if this is even possible, though the numerous Stackflows seem to suggest it is...
I did come across this problem too several months ago, so there's an easy solution. You need to subclass your own GridView, and override the "onMeasure()" method so as to calculate the actual height of your needs. Here is the implementation.
public class ExpandableHeightGridView extends GridView {
boolean expanded = false;
public ExpandableHeightGridView(Context context) {
super(context);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded() {
return expanded;
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isExpanded()) {
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
Hope it helps.

Where to set size of view which is field of class extending RelativeLayout?

I have a class MyLayout extending RelativeLayout which includes View type field. MyLayout object is created in xml layout file, so all properties are set there. I need to programatically set size of View field which depends on size of it's parent (MyLayout).
I was trying to set it in constructor, but when I try to use getWidth() method, it returns 0, so I assume that the size is not yet set inside a constructor. I was also trying to set it in onDraw() method, but when I run an application, this internal View is displayed for like second with it's default size and after that time it's scaled to the right size. Then I tried putting it inside onMeasure() method, but this one is called a few times, so again it doesn't seem to be efficient at all.
So what could be the best place to set it?
This is my class:
public class MyLayout extends RelativeLayout {
private View pointer;
public MyLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public MyLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyLayout(Context context) {
super(context);
init(context);
}
private void init(Context c) {
pointer = new View(c);
pointer.setBackgroundResource(R.drawable.pointer);
addView(pointer);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)pointer.getLayoutParams();
lp.height = (int)(getHeight() * 0.198);
lp.width = (int)(getWidth() * 0.198);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
in your MyLayout class, override onSizeChanged():
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)pointer.getLayoutParams();
lp.height = (int)(getHeight() * 0.198);
lp.width = (int)(getWidth() * 0.198);
};

Custom Progress Bar (without images)

I want to create a progress bar as specified in the image. I've very little idea about how to create a custom view. I checked a lot of tutorials, but couldn't find a starting point. I've no images regarding the progressbar. I'm supposed to draw it. I tried overriding the ondraw method, but I was unable to get the exact look.
Here is the image :
Thanks for your help
First off, you will only need one image of your loading arcs as they are replicable.
http://developer.android.com/guide/topics/ui/custom-components.html
public class CustomView extends View
{
public CustomView(Context context)
{
super(context);
}
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(REFERENCETIBITMAPHERE, 0, 0, null);
}
#Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
private int measureWidth(int measureSpec)
{
int preferred = REFERENCETIBITMAPHERE.getWidth();
return getMeasurement(measureSpec, preferred);
}
private int measureHeight(int measureSpec)
{
int preferred = REFERENCETIBITMAPHERE.getHeight();
return getMeasurement(measureSpec, preferred);
}
private int getMeasurement(int measureSpec, int preferred)
{
int specSize = MeasureSpec.getSize(measureSpec);
int measurement = 0;
switch(MeasureSpec.getMode(measureSpec))
{
case MeasureSpec.EXACTLY:
measurement = specSize;
break;
case MeasureSpec.AT_MOST:
measurement = Math.min(preferred, specSize);
break;
default:
measurement = preferred;
break;
}
return measurement;
}
}
You will need to create your own method to receive some sort of value indicating the loading progress, and then redraw accordingly.
For example:
protected void onDraw(Canvas canvas)
{
// Where loadProgress is an int of some sort.
for(int i = 0; i < loadProgress; i++)
{
canvas.drawBitmap(REFERENCETIBITMAPHERE, REFERENCEBITMAPHERE.getWidth() * i, 0, null);
}
}
I hope this helps. =)
pls try this.
private void showProgressDialog() {
pDlg = new ProgressDialog(activity);
pDlg.setMessage(processMessage);
pDlg.setMax(100);
pDlg.setProgressDrawable(c.getResources().getDrawable(R.drawable.my_progress_bar));
pDlg.setCancelable(false);
pDlg.show();
}
your image = view.getResources().getDrawable(R.drawable.my_progress_bar)
You want to create your own progressbar, then you can override any view class, override the onDraw method and write it down your own code.
If you need some example then I will provide you.

How can i view a video inside a videoview at some specific position?

I am currently trying to implement a videoview that will show a video on a specific position. I can show a fullscreen video with no problem. However whenever i try to show that video inside a frame( a little rectangle for example ) I can only show a part of video in that view. I couldn't fit the video into that view.
I already look for lots of links about scaling a video in android, however I couldnt find any way to do this. Any help about that issue will be helpful.
What i am using is i have 2 different classes. One of them is my video activity class and other one is a helper class:
public class VideoViewCustom extends VideoView {
private int mForceHeight = 0;
private int mForceWidth = 0;
public VideoViewCustom(Context context) {
super(context);
}
public VideoViewCustom(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public VideoViewCustom(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setDimensions(int w, int h) {
this.mForceHeight = h;
this.mForceWidth = w;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(mForceWidth, mForceHeight);
}
}
That class help me to set dimensions of videoview correctly, however i couldnt make video fit into that region. I mean I couldn't scale the video to fit into that region. I dont know whether or not android is autoscaling into given dimensions but i couldnt do it.
May this will help you...
public void onMeasure(int width, int height)
{
getHolder().setFixedSize(width, height);
forceLayout();
setMeasuredDimension(width, height);
invalidate();
}
...and try a RelativeLayout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<VideoView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
I think you have to create a ViewGroup where you can implements onLayout() method.
Here you can set the position of your views directly calling the layout() method for each one of them.
Example:
ViewGroup vg = new ViewGroup(this) {
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int x = getMeasuredWidth();
int y = getMeasuredHeight();
for (int i = 0; i < vg.getChildCount(); i++) {
if(vg.getChildAt(i) instanceof TextView){
vg.getChildAt(i).layout(...);//and so on...
}
}
}
};
Hope helping!!

Categories

Resources