I am drawing a view in canvas with existing views. But it draw below the view. Not exactly on the view.
public class MyView extends View {
Paint paint;
ViewGroup viewGroup;
Context context;
public MyView(Context context, ViewGroup viewGroup) {
super(context);
this.viewGroup = viewGroup;
this.context = context;
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
paint = new Paint();
paint.setColor(context.getResources().getColor(R.color.gray));
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.FILL);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < viewGroup.getChildCount() - 1; ++i) {
View child = viewGroup.getChildAt(i);
Point point = getLocationOnScreen(child);
Rect rect = new Rect();
int x = point.x;
int y = point.y;
rect.left = x;
rect.top = y;
rect.right = x + child.getWidth();
rect.bottom = y + child.getHeight();
canvas.drawRect(rect, paint);
}
/*for (int i = 0; i < viewGroup.getChildCount() - 1; ++i) {
View child = viewGroup.getChildAt(i);
Rect rect = new Rect();
rect.left = child.getLeft();
rect.top = child.getTop();
rect.bottom = child.getBottom();
rect.right = child.getRight();
canvas.drawRect(rect, paint);
}*/
}
public static Point getLocationOnScreen(View view) {
int[] location = new int[2];
view.getLocationOnScreen(location);
return new Point(location[0], location[1]);
}
}
My MainActivity:
public class MainActivity extends AppCompatActivity {
ConstraintLayout constraintLayout;
ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
constraintLayout = findViewById(R.id.parent_view);
imageView = findViewById(R.id.item_profile_img);
imageView.post(() -> {
ViewGroup viewGroup = (ViewGroup) constraintLayout;
constraintLayout.addView(new MyView(MainActivity.this,viewGroup));
});
}
}
activity_main.xml:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText,MissingConstraints"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
tools:ignore="HardcodedText,MissingConstraints"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:id="#+id/parent_view">
<ImageView
android:id="#+id/item_profile_img"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/ic_launcher_background"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription,MissingConstraints" />
<TextView
android:id="#+id/item_student_name_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:text="Student name"
android:textStyle="bold"
app:layout_constraintStart_toEndOf="#+id/item_profile_img" />
<TextView
android:id="#+id/item_student_college"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="8dp"
android:text="Student college"
app:layout_constraintStart_toEndOf="#+id/item_profile_img"
app:layout_constraintTop_toBottomOf="#+id/item_student_name_title" />
<TextView
android:id="#+id/item_student_specialization"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="8dp"
android:text="Student specialization"
app:layout_constraintStart_toEndOf="#+id/item_profile_img"
app:layout_constraintTop_toBottomOf="#+id/item_student_college" />
<TextView
android:id="#+id/item_student_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="8dp"
android:text="Student description"
app:layout_constraintTop_toBottomOf="#+id/item_profile_img"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Please review my code and let me know where I did mistake.
Try This
change you're for loop inside onDraw() like this
for (int i = 0; i < viewGroup.getChildCount() - 1; ++i) {
View child = viewGroup.getChildAt(i);
Rect rect = new Rect();
// int x = point.x;
// int x = point.x;
int x = (int) child.getX() - dpToPx(20);
int y = (int) child.getY() - dpToPx(20);
rect.left = x;
rect.top = y;
rect.right = x + child.getWidth();
rect.bottom = y + child.getHeight();
canvas.drawRect(rect, paint);
}
use a view.getX() and view.getY() it returns proper x and y position of view minus value 20 is the padding of your parent view
public static int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
Related
I use custom view placed over an image view like that
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:orientation="vertical"
android:weightSum="5"
tools:context=".TextRecognitionActivity">
<ImageView
android:id="#+id/surfaceViewImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:adjustViewBounds="true"
android:scaleType="fitXY"
/>
<com.gypsywaiter.app.DragRectView
android:id="#+id/dragRectView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
/>
<Button
android:id="#+id/capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_weight="1"
android:text="Capture"/>
</FrameLayout>
And I draw a rectangle in this view upon user selects and drags as follow
public class DragRectView extends View {
private Paint mRectPaint;
private int mStartX = 0;
private int mStartY = 0;
private int mEndX = 0;
private int mEndY = 0;
private boolean mDrawRect = false;
private TextPaint mTextPaint = null;
private OnUpCallback mCallback = null;
public interface OnUpCallback {
void onRectFinished(Rect rect);
}
public DragRectView(final Context context) {
super(context);
init();
}
public DragRectView(final Context context, final AttributeSet attrs) {
super(context, attrs);
init();
}
public DragRectView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
init();
}
/**
* Sets callback for up
*
* #param callback {#link OnUpCallback}
*/
public void setOnUpCallback(OnUpCallback callback) {
mCallback = callback;
}
/**
* Inits internal data
*/
private void init() {
mRectPaint = new Paint();
mRectPaint.setColor(getContext().getResources().getColor(android.R.color.holo_green_light));
mRectPaint.setStyle(Paint.Style.FILL);
mRectPaint.setStrokeWidth(5); // TODO: should take from resources
mRectPaint.setAlpha(60);
mTextPaint = new TextPaint();
mTextPaint.setColor(getContext().getResources().getColor(android.R.color.holo_green_light));
mTextPaint.setTextSize(20);
}
#Override
public boolean onTouchEvent(final MotionEvent event) {
// TODO: be aware of multi-touches
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDrawRect = false;
mStartX = (int) event.getX();
mStartY = (int) event.getY();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
final int x = (int) event.getX();
final int y = (int) event.getY();
Log.d("logger", x + "//" + y);
//if (!mDrawRect || Math.abs(x - mEndX) > 5 || Math.abs(y - mEndY) > 5) {
mEndX = x;
mEndY = y;
invalidate();
//}
mDrawRect = true;
break;
case MotionEvent.ACTION_UP:
int[] location = new int[2];
getLocationOnScreen(location);
invalidate();
if (mCallback != null) {
mCallback.onRectFinished(new Rect(Math.min(mStartX, mEndX), Math.min(mStartY, mEndY),
Math.max(mEndX, mStartX), Math.max(mStartY, mEndY)));
}
break;
default:
break;
}
return true;
}
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(Math.min(mStartX, mEndX), Math.min(mStartY, mEndY),
Math.max(mEndX, mStartX), Math.max(mEndY, mStartY), mRectPaint);
}
When I try to extract that selected part like that,
dragRectView.setOnUpCallback(new DragRectView.OnUpCallback() {
#Override
public void onRectFinished(Rect rect) {
Bitmap nBitmap = Bitmap.createBitmap(loadedImage,rect.top, rect.left , rect.bottom, rect.right);
}
});
I always get the wrong area and some times crash that x must be less than width. I think it is something related to coordinates but I can't figure it out.
The problem was in the difference between image resolution and the ImageView dimensions.
Solution is:
Resize the bitmap image to be the same width and height of the ImageView and it will work.
Im making a simple drawing app using canvas. The problem is when I set a background image (of a black board) for the canvas, it only occupies ~66% of the screen. See screenshot/link:
Canvas View
I want my canvas view to occupy the entire screen except the bottom part that RelativeLayout with id parLayout occupies.
What am I doing wrong in my code? Here is what I have:
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static int wandToUse1;
public static int wandToUse2;
public static int wandToUse3;
private ViewGroup rootLayout;
private ViewGroup rlWand2;
private int _xDelta;
private int _yDelta;
private RelativeLayout pl;
private RelativeLayout wn2;
private RelativeLayout wn1;
ImageView w1;
ImageView w2;
boolean clicked1 = false;
boolean clicked2 = false;
RelativeLayout ll;
public static int X;
public static int Y;
CanvasView canvasView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.parLayout);
canvasView = new CanvasView(MainActivity.this);
rootLayout.addView(canvasView);
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight() / 2);
layoutParams1w2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
canvasView.setLayoutParams(layoutParams1w2);
ll = (RelativeLayout) findViewById(R.id.parLayout);
w1 = (ImageView) findViewById(R.id.wand1);
w2 = (ImageView) findViewById(R.id.wand2);
w1.setImageResource(wandToUse1);
w2.setImageResource(wandToUse2);
pl = (RelativeLayout) findViewById(R.id.coordAct);
wn1 = (RelativeLayout) findViewById(R.id.rlw1);
wn2 = (RelativeLayout) findViewById(R.id.rlw2);
w1.setOnTouchListener(new ChoiceTouchListener());
w2.setOnTouchListener(new ChoiceTouchListener());
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
public class ChoiceTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent event) {
if (!clicked1) {
rootLayout = (ViewGroup) w1.getParent();
if (rootLayout != null) {
rootLayout.removeView(w1);
}
rlWand2 = (ViewGroup) w2.getParent();
if (rlWand2 != null) {
rlWand2.removeView(w2);
}
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(300, 300);
pl.addView(w1);
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(250, 250);
wn2.addView(w2);
layoutParams1w2.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
w1.setLayoutParams(layoutParams1);
w2.setLayoutParams(layoutParams1w2);
clicked1 = true;
clicked2 = false;
}
X = (int) event.getRawX();
Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
canvasView.dispatchTouchEvent(event);
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
view.setLayoutParams(layoutParams);
canvasView.dispatchTouchEvent(event);
break;
}
rootLayout.invalidate();
return true;
}
}
CanvasView.java
public class CanvasView extends View{
private Bitmap sourceBitmap;
private Canvas sourceCanvas = new Canvas();
private Paint destPaint = new Paint();
public static Path destPath = new Path();
Bitmap rawBitmap;
public int width;
public int height;
public CanvasView(Context context) {
super(context);
init(context);
}
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CanvasView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
width = metrics.widthPixels;
height = metrics.heightPixels;
//converting drawable resource file into bitmap
rawBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.blackboard);
rawBitmap = Bitmap.createScaledBitmap(rawBitmap, width, height, false);
Rect frameToDraw = new Rect(0, 0, width, height);
RectF whereToDraw = new RectF(0, 0, width, height);
//converting bitmap into mutable bitmap
sourceBitmap = Bitmap.createBitmap(rawBitmap.getWidth(), rawBitmap.getHeight(), Bitmap.Config.ARGB_8888);
sourceCanvas.setBitmap(sourceBitmap);
sourceCanvas.drawBitmap(rawBitmap, frameToDraw,whereToDraw, null);
destPaint.setAlpha(0);
destPaint.setAntiAlias(true);
destPaint.setStyle(Paint.Style.STROKE);
destPaint.setStrokeJoin(Paint.Join.ROUND);
destPaint.setStrokeCap(Paint.Cap.ROUND);
//change this value as per your need
destPaint.setStrokeWidth(50);
destPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
}
#Override
protected void onDraw(Canvas canvas)
{
sourceCanvas.drawPath(destPath, destPaint);
canvas.drawBitmap(sourceBitmap, 0, 0, null);
super.onDraw(canvas);
}
public void clearCanvas() {
destPath.reset();
invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
destPath.moveTo(MainActivity.X, MainActivity.Y-360);
break;
case MotionEvent.ACTION_MOVE:
destPath.lineTo(MainActivity.X, MainActivity.Y-360);
break;
default:
return false;
}
invalidate();
return true;
}
activity_main.xml
<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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/coordAct"
tools:context="com.simplepaintapp.MainActivity">
<RelativeLayout
android:id="#+id/parLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="3"
android:background="#color/colorAccent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:background="#BA9DF7"
android:gravity="bottom"
android:orientation="vertical">
<LinearLayout
android:id="#+id/parentLL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="5">
<RelativeLayout
android:id="#+id/rlw1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginRight="0dp"
android:layout_weight="1"
android:background="#color/colorPrimary">
<ImageView
android:id="#+id/wand1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:src="#mipmap/pen" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/rlw2"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginRight="0dp"
android:layout_weight="1"
android:background="#color/colorPrimary">
<ImageView
android:id="#+id/wand2"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:src="#drawable/eraser" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
Thank You!
I got it! I was a bit tired yesterday and couldn't think.
Just fix this line in MainActivity.java
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight() / 2);
To
RelativeLayout.LayoutParams layoutParams1w2 = new RelativeLayout.LayoutParams(getScreenWidth(), getScreenHeight());
I have a Custom View that extends RelativeLayout with overridden onDraw() method so that it looks like a message bubble. This View is in the LinearLayout. When I try to fill this custom View with content, part of its shape is pushed out of the LinearLayout. How to prevent this behaviour?How to prevent this behaviour?
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:id="#+id/chat_message_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:text="2:46pm"
android:textSize="#dimen/splash_4_user_name_text_size" />
<com.mypackage.RightBasedMessage
android:id="#+id/chat_message_field"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="#dimen/splash_3_comment_padding"
android:paddingLeft="#dimen/splash_3_comment_end_padding"
android:paddingRight="#dimen/chat_message_field_beginning_padding"
android:paddingTop="#dimen/splash_3_comment_padding">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi :)"
android:textColor="#color/white_text_color" />
</com.mypackage.RightBasedMessage>
</LinearLayout>
Here is my Custom View:
public class RightBasedMessage extends RelativeLayout {
private Paint paint;
private Path path;
private Point pointleftTop;
private Point pointRightTop;
private Point pointRightBottom;
private Point pointLeftBottom;
private float corner;
private Context context;
private int color = R.color.chat_my_message_field_color;
public RightBasedMessage(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
corner = getResources().getDimension(R.dimen.message_container_corner);
paint = new Paint();
path = new Path();
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.FILL);
this.setWillNotDraw(false);
}
public void setMessageBackground(int color){
this.color = color;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
pointRightTop = new Point(width-(int)corner, (int)corner/2);
pointRightBottom = new Point(width-(int)corner, height);
pointLeftBottom = new Point(0, height);
pointleftTop = new Point(0, 0);
path.reset();
path.moveTo(corner, 0);
path.lineTo(width, 0);
path.quadTo(pointRightTop.x, pointRightTop.y, width-corner, corner+corner/2);
path.lineTo(width-corner, height-corner);
path.quadTo(pointRightBottom.x, pointRightBottom.y, width - corner*2, height);
path.lineTo(corner, height);
path.quadTo(pointLeftBottom.x, pointLeftBottom.y, 0, height-corner);
path.lineTo(0, corner);
path.quadTo(pointleftTop.x, pointleftTop.y, corner, 0);
paint.setColor(ContextCompat.getColor(context, color));
canvas.drawPath(path, paint);
path.close();
}
}
have you tried this?
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
>
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.
I am looking to implement some sort of "canvas" where you can place X number of TextViews/Links at "random positions" (Positioned like in the image below). You would then be able to scroll this "canvas" view left or right continuously and the view will repeat/be circular (sort of like a HTML marquee except that you are doing the scrolling manually). In the most simplest of cases I am just looking to have horizontal scrolling - but an example of a more "complex case" is where you can do "sphere scrolling" - see the example below from Appy Geek. (For now I am just interested in the horizontal scrolling)
Example from Appy Geek:
Well this will get you started, I have implemented a simple tag cloud using both approaches (i.e. by extending View and ViewGroup) that keeps rotating. You can use this logic in your custom ViewGroup which positions its View's accordingly. After that add clickable TextViews inside that layout and handle touch events.
Final result (ofcourse its rotating, look closer):
Lot of things can be improved in the following code.
BY EXTENDING ViewGroup:
Put this in xml layout:
<com.vj.tagcloud.TagCloudLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</com.vj.tagcloud.TagCloudLayout>
TagCloudLayout class:
import java.util.Random;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class TagCloudLayout extends ViewGroup {
final Random mRandom = new Random();
private float mRotateAngle;
private Handler mHandler = new Handler();
private float rotateAngleDegree;
public TagCloudLayout(Context context) {
super(context);
}
public TagCloudLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TagCloudLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final float radius = Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2F;
float halfWidth = getMeasuredWidth() / 2F;
float halfHeight = getMeasuredHeight() / 2F;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
float sinTheta = (float) Math.sin(lp.theta);
float x = (int) (radius * Math.cos(lp.fi + mRotateAngle)
* sinTheta);
if (child instanceof TextView) {
((TextView) child)
.setTextSize(15 * ((radius - x) / radius) + 10);
}
measureChild(child, widthMeasureSpec, heightMeasureSpec);
// http://en.wikipedia.org/wiki/Spherical_coordinates
lp.x = (int) ((halfWidth + radius * Math.sin(lp.fi + mRotateAngle)
* sinTheta) - /* for balancing on x-axis */(child
.getMeasuredWidth() / 2F));
lp.y = (int) (halfHeight + radius * Math.cos(lp.theta)-/* for balancing on y-axis */(child
.getMeasuredHeight() / 2F));
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
rotateAngleDegree += 5;
mRotateAngle = (float) Math.toRadians(rotateAngleDegree);
requestLayout();
mHandler.postDelayed(this, 40);
}
}, 40);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mHandler.removeCallbacksAndMessages(null);
}
#Override
public void addView(View child, int index,
android.view.ViewGroup.LayoutParams params) {
super.addView(child, index, params);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
lp.fi = (float) Math.toRadians(mRandom.nextInt(360));
lp.theta = (float) Math.toRadians(mRandom.nextInt(360));
}
#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 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;
float fi, theta;
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LayoutParams(int w, int h) {
super(w, h);
}
}
}
BY EXTENDING View:
Put this in xml layout:
<com.vj.wordtap.TagCloud
android:layout_width="match_parent"
android:layout_height="match_parent" />
and this in java code:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
public class TagCloud extends View {
private List<String> mItems = new ArrayList<String>();
private List<Angles> mAngles = new ArrayList<Angles>();
private Camera mCamera = new Camera();
private TextPaint mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
private Handler mHandler = new Handler();
private float mRotateAngle;
private float rotateAngleDegree;
public static class Angles {
float fi, theta;
}
public TagCloud(Context context) {
super(context);
init();
}
public TagCloud(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TagCloud(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
List<String> items = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
items.add("item:" + i);
}
setItems(items);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(canvas.getWidth() / 2F, canvas.getHeight() / 2F);
mTextPaint.setColor(Color.BLACK);
final float radius = 100;
mCamera.setLocation(0, 0, -100);
for (int i = 0; i < mItems.size(); i++) {
String item = mItems.get(i);
Angles xyz = mAngles.get(i);
mCamera.save();
canvas.save();
float sinTheta = (float) Math.sin(xyz.theta);
float x = (float) (radius * Math.cos(xyz.fi + mRotateAngle) * sinTheta);
float y = (float) (radius * Math.sin(xyz.fi + mRotateAngle) * sinTheta);
float z = (float) (radius * Math.cos(xyz.theta));
// mapping coordinates with Android's coordinates
// http://en.wikipedia.org/wiki/Spherical_coordinates
mCamera.translate(y, z, x);
mCamera.applyToCanvas(canvas);
// http://en.wikipedia.org/wiki/Spherical_coordinates
// set size based on x-Axis that is coming towards us
mTextPaint.setTextSize(20 * ((100 - x) / 100) + 10);
canvas.drawText(item, 0, 0, mTextPaint);
mCamera.restore();
canvas.restore();
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
rotateAngleDegree += 5;
mRotateAngle = (float) Math.toRadians(rotateAngleDegree);
invalidate();
mHandler.postDelayed(this, 40);
}
}, 40);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mHandler.removeCallbacksAndMessages(null);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void setItems(List<String> items) {
mItems = items;
final Random ran = new Random();
final List<Angles> xyzList = mAngles;
xyzList.clear();
for (int i = 0; i < items.size(); i++) {
Angles xyz = new Angles();
float fi = (float) Math.toRadians(ran.nextInt(360));
xyz.fi = fi;
float theta = (float) Math.toRadians(ran.nextInt(360));
xyz.theta = theta;
xyzList.add(xyz);
}
}
}