I am trying to put a custom view into scrollView. This is my custom view MyCustomLayout.java
public class MyCustomLayout extends ViewGroup {
private static final int UNEVEN_GRID_PENALTY_MULTIPLIER = 10;
private int mMaxChildWidth = 0;
private int mMaxChildHeight = 0;
public MyCustomLayout(Context context) {
super(context, null);
}
public MyCustomLayout(Context context, AttributeSet attrs) {
super(context, attrs, 0);
}
public MyCustomLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMaxChildWidth = 0;
mMaxChildHeight = 0;
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth());
mMaxChildHeight = Math.max(mMaxChildHeight, child.getMeasuredHeight());
}
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
mMaxChildWidth, MeasureSpec.EXACTLY);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
mMaxChildHeight, MeasureSpec.EXACTLY);
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
setMeasuredDimension(
resolveSize(mMaxChildWidth, widthMeasureSpec),
resolveSize(mMaxChildHeight, heightMeasureSpec));
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int width = r - l;
int height = b - t;
final int count = getChildCount();
// Calculate the number of visible children.
int visibleCount = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
++visibleCount;
}
if (visibleCount == 0) {
return;
}
int bestSpaceDifference = Integer.MAX_VALUE;
int spaceDifference;
int hSpace = 0;
int vSpace = 0;
int cols = 1;
int rows;
while (true) {
rows = (visibleCount - 1) / cols + 1;
hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));
spaceDifference = Math.abs(vSpace - hSpace);
if (rows * cols != visibleCount) {
spaceDifference *= UNEVEN_GRID_PENALTY_MULTIPLIER;
}
if (spaceDifference < bestSpaceDifference) {
bestSpaceDifference = spaceDifference;
if (rows == 1) {
break;
}
} else {
--cols;
rows = (visibleCount - 1) / cols + 1;
hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));
break;
}
++cols;
}
hSpace = Math.max(0, hSpace);
vSpace = Math.max(0, vSpace);
width = (width - hSpace * (cols + 1)) / cols;
height = (height - vSpace * (rows + 1)) / rows;
int left, top;
int col, row;
int visibleIndex = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
row = visibleIndex / cols;
col = visibleIndex % cols;
left = hSpace * (col + 1) + width * col;
top = vSpace * (row + 1) + height * row;
child.layout(left, top,
(hSpace == 0 && col == cols - 1) ? r : (left + width),
(vSpace == 0 && row == rows - 1) ? b : (top + height));
++visibleIndex;
}
}
}
When I use in a LinearLayout with those xml code. It works fine.
<com.crazyCoder.androiddeshboard.MyCustomLayout
android:id="#+id/layout_custom"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#f8f9fe" >
</com.crazyCoder.androiddeshboard.MyCustomLayout>
But when I put into a scrollView like this
<ScrollView
android:id="#+id/scrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffd9f4">
<com.crazyCoder.androiddeshboard.MyCustomLayout
android:id="#+id/layout_custom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f8f9fe" >
</com.crazyCoder.androiddeshboard.MyCustomLayout>
</ScrollView>
The custom view overlapping by the scrollView. The output like this.
ScrollView Output
Please Help me. Thanks in advance.
Try put FrameLayout in ScrollView and put MyCustomLatyout in FrameLayout.
<ScrollView
android:id="#+id/scrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffd9f4">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.crazyCoder.androiddeshboard.MyCustomLayout
android:id="#+id/layout_custom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f8f9fe" >
</com.crazyCoder.androiddeshboard.MyCustomLayout>
</FrameLayout>
</ScrollView>
Related
I am trying to make a scrollable layout, where I would have a single bigger custom view at the start and dynamic amount of smaller TextViews after it.
Like this:
|-----|---Start of devices screen
| |
| | -Custom view 1
| |
|-----|
| |---TextView & End of devices screen
|-----|
|-----|
| |
|-----|
The custom view is a view where I do some drawing in onDraw().
I have been trying to fiddle with the onMeasure() method, layout_height and layout_weight properties, but I am unable to get a satisfactory result. I always end up with a unscrollable layout or one without the custom view. Only way I have been able to get the functionality is by setting the custom view's height to some 'dp' value, but I would like it leave the same physical amount of space in the botto of the screen.
Is something like this possible with the tools Android provides, or would this need some custom view for the scrolling too? How would I go about implementing this?
Edit: To clarify, I need the first element I have in the ScrollView to initially either fill the whole visible area of the ScrollView or leave a small space under it that is constant on every device.
Use Flow Layout In place of your custom layout
find flow layout implementation link
https://docs.google.com/file/d/0B_VKZCqEnHblNDdiY2UxODgtYWNhNS00MmU4LWE4NDMtZjQ1OWI5MDMxZTVh/edit?num=50&sort=name&layout=list&pli=1#
package com.example.android.layout;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class FlowLayout extends ViewGroup {
private int mHorizontalSpacing;
private int mVerticalSpacing;
private Paint mPaint;
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
try {
mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 0);
mVerticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 0);
} finally {
a.recycle();
}
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(0xffff0000);
mPaint.setStrokeWidth(2.0f);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec) - getPaddingRight();
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
boolean growHeight = widthMode != MeasureSpec.UNSPECIFIED;
int width = 0;
int height = getPaddingTop();
int currentWidth = getPaddingLeft();
int currentHeight = 0;
boolean breakLine = false;
boolean newLine = false;
int spacing = 0;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
spacing = mHorizontalSpacing;
if (lp.horizontalSpacing >= 0) {
spacing = lp.horizontalSpacing;
}
if (growHeight && (breakLine || currentWidth + child.getMeasuredWidth() > widthSize)) {
height += currentHeight + mVerticalSpacing;
currentHeight = 0;
width = Math.max(width, currentWidth - spacing);
currentWidth = getPaddingLeft();
newLine = true;
} else {
newLine = false;
}
lp.x = currentWidth;
lp.y = height;
currentWidth += child.getMeasuredWidth() + spacing;
currentHeight = Math.max(currentHeight, child.getMeasuredHeight());
breakLine = lp.breakLine;
}
if (!newLine) {
height += currentHeight;
width = Math.max(width, currentWidth - spacing);
}
width += getPaddingRight();
height += getPaddingBottom();
setMeasuredDimension(resolveSize(width, widthMeasureSpec),
resolveSize(height, heightMeasureSpec));
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
}
}
#Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean more = super.drawChild(canvas, child, drawingTime);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.horizontalSpacing > 0) {
float x = child.getRight();
float y = child.getTop() + child.getHeight() / 2.0f;
canvas.drawLine(x, y - 4.0f, x, y + 4.0f, mPaint);
canvas.drawLine(x, y, x + lp.horizontalSpacing, y, mPaint);
canvas.drawLine(x + lp.horizontalSpacing, y - 4.0f, x + lp.horizontalSpacing, y + 4.0f, mPaint);
}
if (lp.breakLine) {
float x = child.getRight();
float y = child.getTop() + child.getHeight() / 2.0f;
canvas.drawLine(x, y, x, y + 6.0f, mPaint);
canvas.drawLine(x, y + 6.0f, x + 6.0f, y + 6.0f, mPaint);
}
return more;
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
#Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
#Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
#Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p.width, p.height);
}
public static class LayoutParams extends ViewGroup.LayoutParams {
int x;
int y;
public int horizontalSpacing;
public boolean breakLine;
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout_LayoutParams);
try {
horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_horizontalSpacing, -1);
breakLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_breakLine, false);
} finally {
a.recycle();
}
}
public LayoutParams(int w, int h) {
super(w, h);
}
}
}
<resources>
<declare-styleable name="FlowLayout">
<attr name="horizontalSpacing" format="dimension" />
<attr name="verticalSpacing" format="dimension" />
</declare-styleable>
<declare-styleable name="FlowLayout_LayoutParams">
<attr name="layout_breakLine" format="boolean" />
<attr name="layout_horizontalSpacing" format="dimension" />
</declare-styleable>
</resources>
I want to implement chip something like this:
chip
But since I've a predefined Array Adapter & just need to put its values into this chip & I want to set these chips to a Textview or simply View. I've tried many chip libraries but all of them gave some kind of error while adding to dependencies.
I just need to implement chips for the look of the app & not search functionality so can anyone help me in this & if you have any better ideas then please feel free to share.
Finally I did it like this with the help of a nine patch image chip.9.png & FlowLayout:
MainActivity:
LinearLayout llTemp = new LinearLayout(this);
llTemp.setOrientation(LinearLayout.HORIZONTAL);
llTemp.setBackgroundResource(R.drawable.chip);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
llTemp.setLayoutParams(params);
llTemp.setGravity(Gravity.CENTER_VERTICAL);
TextView tv = new TextView(this);
tv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
tv.setPadding(0, 0, 5, 0);
tv.setText("Some text");
CircularImageView iv = new CircularImageView(this);
LinearLayout.LayoutParams ivParams = new LinearLayout.LayoutParams(50, 50);
ivParams.setMargins(0, 0, 5, 0);
iv.setLayoutParams(ivParams);
iv.setBorderWidth(0);
Picasso.with(this).load(IMAGE_LINK + IMAGE_FILE).into(iv);
ImageView ivCloseBtn = new ImageView(this);
ivCloseBtn.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
ivCloseBtn.setPadding(2, 2, 2, 2);
ivCloseBtn.setBackgroundResource(R.drawable.icon_close);
FlowLayout.java:
public class FlowLayout extends ViewGroup {
private int paddingHorizontal;
private int paddingVertical;
public FlowLayout(Context context) {
super(context);
init();
}
public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
paddingHorizontal = getResources().getDimensionPixelSize(R.dimen.flowlayout_horizontal_padding);
paddingVertical = getResources().getDimensionPixelSize(R.dimen.flowlayout_vertical_padding);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int childLeft = getPaddingLeft();
int childTop = getPaddingTop();
int lineHeight = 0;
// 100 is a dummy number, widthMeasureSpec should always be EXACTLY for FlowLayout
int myWidth = resolveSize(100, widthMeasureSpec);
int wantedHeight = 0;
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
if (child.getVisibility() == View.GONE) {
continue;
}
// let the child measure itself
child.measure(
getChildMeasureSpec(widthMeasureSpec, 0, child.getLayoutParams().width),
getChildMeasureSpec(heightMeasureSpec, 0, child.getLayoutParams().height));
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
// lineheight is the height of current line, should be the height of the highest view
lineHeight = Math.max(childHeight, lineHeight);
if (childWidth + childLeft + getPaddingRight() > myWidth) {
// wrap this line
childLeft = getPaddingLeft();
childTop += paddingVertical + lineHeight;
lineHeight = childHeight;
}
childLeft += childWidth + paddingHorizontal;
}
wantedHeight += childTop + lineHeight + getPaddingBottom();
setMeasuredDimension(myWidth, resolveSize(wantedHeight, heightMeasureSpec));
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int childLeft = getPaddingLeft();
int childTop = getPaddingTop();
int lineHeight = 0;
int myWidth = right - left;
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
if (child.getVisibility() == View.GONE) {
continue;
}
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
lineHeight = Math.max(childHeight, lineHeight);
if (childWidth + childLeft + getPaddingRight() > myWidth) {
childLeft = getPaddingLeft();
childTop += paddingVertical + lineHeight;
lineHeight = childHeight;
}
child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childLeft += childWidth + paddingHorizontal;
}
}}
& then in Main Activity: flowLayout.addView(llTemp)
& flow layout within xml file(mainactivity):
<ScrollView android:id="#+id/sv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<com.example.FlowLayout
android:id="#+id/fl"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
Final Product: final_chip_image
I am trying to hide a child in a view during onLayout. The problem is the postInvalidate is not recalling onLayout after i hide the child
public class EllipseFlowLayout extends ViewGroup {
private int paddingHorizontal;
private int paddingVertical;
private int mMaxLines = -1;
private EllipseView mEllipse;
private View ellipseView;
private int numHidden;
private boolean mEllipseRemoved = true;
public EllipseFlowLayout(Context context) {
super(context);
init();
}
public void setMaxLines(int max) {
mMaxLines = max;
}
public EllipseFlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public EllipseFlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
paddingHorizontal = getResources().getDimensionPixelSize(R.dimen.flowlayout_horizontal_padding);
paddingVertical = getResources().getDimensionPixelSize(R.dimen.flowlayout_vertical_padding);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childLeft = getPaddingLeft();
int childTop = getPaddingTop();
int lineHeight = 0;
int numLines = 1;
// 100 is a dummy number, widthMeasureSpec should always be EXACTLY for FlowLayout
int myWidth = resolveSize(MeasureSpec.EXACTLY, widthMeasureSpec);
int wantedHeight = 0;
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
if (child.getVisibility() == View.GONE || child.getTag() == GONE) {
continue;
}
// let the child measure itself
child.measure(
getChildMeasureSpec(widthMeasureSpec, 0, child.getLayoutParams().width),
getChildMeasureSpec(heightMeasureSpec, 0, child.getLayoutParams().height));
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
// lineheight is the height of current line, should be the height of the heightest view
lineHeight = Math.max(childHeight, lineHeight);
if (childWidth + childLeft + getPaddingRight() > myWidth) {
// wrap this line
childLeft = getPaddingLeft();
childTop += paddingVertical + lineHeight;
lineHeight = childHeight;
numLines++;
Log.d("TEST", "measure" + numLines);
}
childLeft += childWidth + paddingHorizontal;
}
wantedHeight += childTop + lineHeight + getPaddingBottom();
setMeasuredDimension(myWidth, resolveSize(wantedHeight, heightMeasureSpec));
}
#Override
public void addView(View child) {
//super.addView(child);
if (mEllipseRemoved) {
addEllipseView();
}
super.addView(child, getChildCount() - 1);
}
public void setEllipseView(EllipseView ellipse) {
mEllipse = ellipse;
ellipseView = mEllipse.getView();
}
#Override
public void removeAllViews() {
mEllipseRemoved = true;
super.removeAllViews();
}
private void addEllipseView() {
mEllipseRemoved = false;
if (ellipseView.getParent() != null) {
((ViewGroup) ellipseView.getParent()).removeView(ellipseView);
}
ellipseView.setVisibility(View.GONE);
addView(ellipseView);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int childLeft = getPaddingLeft();
int childTop = getPaddingTop();
int lineHeight = 0;
int myWidth = right - left;
int lineNum = 1;
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
if (child.getVisibility() == View.GONE) {
continue;
}
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
lineHeight = Math.max(childHeight, lineHeight);
if (childWidth + childLeft + getPaddingRight() > myWidth) {
childLeft = getPaddingLeft();
childTop += paddingVertical + lineHeight;
lineHeight = childHeight;
lineNum++;
Log.d("TEST", "layout" + lineNum);
}
child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childLeft += childWidth + paddingHorizontal;
}
if (lineNum > mMaxLines) {
// if (ellipseView.getVisibility() == View.GONE) {
// ellipseView.setVisibility(VISIBLE);
// }
//Skip the last view which is the hidden one
int at = numHidden;
if (at < getChildCount() && getChildAt(at) != null) {
View child = getChildAt(at);
numHidden++;
if (child.getVisibility() == View.VISIBLE) {
child.setVisibility(View.GONE);
child.setTag(GONE);
requestLayout();
}
}
if (mEllipse.getCount() != numHidden) {
mEllipse.setEllipseSize(numHidden);
}
}
}
/**
* Was removed so semi untested but leaving for possible use later
*
* #param max max children
*/
public void setMaxChildren(int max) {
}
}
Hide the views in onDraw remember to call this.setWillNotDraw(false);
I am using this flow layout class to arrange dynamically created TextView in multiple lines but i have got following issues:
The height of this layout doesn't behave as WRAP_CONTENT(as shown in
image given in the link).
I am placing this layout toRightOf an another static
TextViews(To,Cc). It leaves a margin in left equal to TextView width
in every line(as shown in image given in the link).
I want to delete this margin when content switches to next line. How to resolve this?
Any help would be appreciated.
public class FlowLayout extends ViewGroup
{
private int paddingHorizontal;
public FlowLayout(Context context)
{
super(context);
init();
}
public FlowLayout(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public FlowLayout(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
private void init()
{
paddingHorizontal = getResources().getDimensionPixelSize(R.dimen.flowlayout_horizontal_padding);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int childLeft = getPaddingLeft();
int childTop = getPaddingTop();
int lineHeight = 0;
int myWidth = resolveSize(100, widthMeasureSpec);
int wantedHeight = 0;
for (int i = 0; i < getChildCount(); i++)
{
final View child = getChildAt(i);
if (child.getVisibility() == View.GONE)
{
continue;
}
child.measure(getChildMeasureSpec(widthMeasureSpec, 0, child.getLayoutParams().width), getChildMeasureSpec(heightMeasureSpec, 0, child.getLayoutParams().height));
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
lineHeight = Math.max(childHeight, lineHeight);
if (childWidth + childLeft + getPaddingRight() > myWidth)
{
childLeft = getPaddingLeft();
childTop += lineHeight;
lineHeight = childHeight;
}
childLeft += childWidth + paddingHorizontal;
}
wantedHeight += childTop + lineHeight + getPaddingBottom();
setMeasuredDimension(myWidth, resolveSize(wantedHeight, heightMeasureSpec));
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
int childLeft = getPaddingLeft();
int childTop = getPaddingTop();
int lineHeight = 0;
int myWidth = right - left;
for (int i = 0; i < getChildCount(); i++)
{
final View child = getChildAt(i);
if (child.getVisibility() == View.GONE)
{
continue;
}
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
lineHeight = Math.max(childHeight, lineHeight);
if (childWidth + childLeft + getPaddingRight() > myWidth)
{
childLeft = getPaddingLeft();
childTop += lineHeight;
lineHeight = childHeight;
}
child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childLeft += childWidth + paddingHorizontal;
}
}
}
I am using it in my xml like this:
<RelativeLayout
android:id="#+id/main_relative_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:id="#+id/To_textView_wrapper_relative_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/To_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="#string/to"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp" />
<PackageName.FlowLayout
android:id="#+id/flow_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/To_textView" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/Cc_textView_wrapper_relative_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/To_textView_wrapper_relative_layout" >
<TextView
android:id="#+id/PhoneNo_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="#string/cc"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp" />
<PackageName.FlowLayout
android:id="#+id/flow_container1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/Cc_textView" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/Bcc_textView_wrapper_relative_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/PhoneNo_textView_wrapper_relative_layout" >
<TextView
android:id="#+id/Bcc_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="#string/bcc"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp" />
<PackageName.FlowLayout
android:id="#+id/flow_container2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/Bcc_textView" />
</RelativeLayout>
</RelativeLayout>
I am new on Android. I am working on simple Sudoku solver and I have problem with my view.
My SolverView contain on Custom View embedded into a layout that contains 2 buttons.
When I click on a cell of sudoku grid, a keypad dialog appear that allow me to choose the number for that cell. However, after click on a number on keypad, my sudoku grid not display it immediately although the onDraw() method was called. Instead, it only update on the next time I touch screen.
Following is the code
public class SolverView extends View{
private String TAG = "Solver View";
private int size;
private Solver solver;
private static int selU, selV;
public SolverView(Context context) {
super(context);
this.solver = (Solver) context;
setFocusable(true);
setFocusableInTouchMode(true);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
public SolverView(Context context, AttributeSet attrs) {
super(context, attrs);
this.solver = (Solver) context;
setFocusable(true);
setFocusableInTouchMode(true);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
public SolverView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.solver = (Solver) context;
setFocusable(true);
setFocusableInTouchMode(true);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
public int getBoardSize() {
int height = getHeight();
int width = getWidth();
return Math.min(height, width);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
size = getBoardSize();
int cellSize = size / 9;
Paint light = new Paint();
light.setColor(getResources().getColor(R.color.puzzle_light));
Paint dark = new Paint();
dark.setColor(getResources().getColor(R.color.puzzle_dark));
dark.setTypeface(Typeface.DEFAULT_BOLD);
for (int i = 0; i <= 9; i++) {
canvas.drawLine(i * cellSize, 0, i * cellSize, size, light);
if (i % 3 == 0)
canvas.drawLine(i * cellSize, 0, i * cellSize, size, dark);
}
for (int i = 0; i <= 9; i++) {
canvas.drawLine(0, i * cellSize, size, i * cellSize, light);
if (i % 3 == 0)
canvas.drawLine(0, i * cellSize, size, i * cellSize, dark);
}
Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG);
foreground.setColor(getResources().getColor(R.color.puzzle_dark));
foreground.setStyle(Style.FILL);
foreground.setTextSize(cellSize * 0.75f);
foreground.setTextAlign(Paint.Align.CENTER);
FontMetrics fm = foreground.getFontMetrics();
float x = cellSize / 2 - (fm.ascent + fm.descent) / 2;
float y = cellSize / 2 ;
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
canvas.drawText(this.solver.getCellString(i, j), j * cellSize + y, i * cellSize + x, foreground);
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN)
return super.onTouchEvent(event);
int cellSize = size / 9;
int i = (int)event.getY() / cellSize;
int j = (int)event.getX() / cellSize;
if (i < 0 || i > 8 || j < 0 || j > 8)
return false;
this.selU = i;
this.selV = j;
Log.d(TAG, "onTouchEvent: " + selU + " , " + selV);
this.solver.showKeypad(i, j);
invalidate();
return true;
}
public void setCell(int t) {
Log.d(TAG, "in setCell: t = " + t);
Log.d(TAG, "in setCell: selU = " + selU);
Log.d(TAG, "in setCell: selV = " + selV);
if (solver.setCellIfValid(selU, selV, t)) {
Log.d(TAG, "setCell: going to invalidate()");
Log.d(TAG, "setCell: value change: " + solver.a[selU][selV]);
invalidate();
}
}
}
And this is the structure of layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/zero"
android:paddingLeft="#dimen/zero"
android:paddingRight="#dimen/zero"
android:paddingTop="#dimen/zero"
tools:context="com.trungkienioicamp.helloworld.Solver" >
<com.trungkienioicamp.helloworld.SolverView
android:id="#+id/board"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" />
<Button
android:id="#+id/clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="74dp"
android:layout_marginLeft="29dp"
android:text="Clear" />
<Button
android:id="#+id/solve"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/clear"
android:layout_alignBottom="#+id/clear"
android:layout_alignParentRight="true"
android:layout_marginRight="61dp"
android:text="Solve" />
Can anyone suggest me the solution for this one? Thank for reading
UPDATED: The problem gone when I set the content view of main activity as solverView instance
setContentView(solverView);
But it will not work when I set the content view as a layout
setContentView(R.layout.activity_solver);
Instead, it only update on the next time I touch screen
Try to call invalidate your instance of SolverView after click on a number on keypad.