I want to make a note editor. It will have an EditText with lines. Here is my code:
LinedEditText.java
public class LinedEditText extends EditText {
private Rect mRect;
private Paint mPaint;
public LinedEditText(Context context) {
super(context);
// TODO Auto-generated constructor stub
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(Color.BLUE); //SET YOUR OWN COLOR HERE
}
#Override
protected void onDraw(Canvas canvas) {
//int count = getLineCount();
int height = getHeight();
int line_height = getLineHeight();
int count = height / line_height;
if (getLineCount() > count)
count = getLineCount();
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);//first line
for (int i = 0; i < count; i++) {
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
baseline += getLineHeight();//next line
}
super.onDraw(canvas);
}
TextEditorActivity.java
public class TextEditorActivity extends Activity {
private LinedEditText text;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.text=new LinedEditText(getApplicationContext());
this.setContentView(text);
}
}
And result:
result http://bekirmavus.com/k-resimler/image/android/device-2012-07-17-222950.png
What mistake am i making?
Thanks...
The line are being drawn from the position of the cursor on down. Simply move the cursor's default position from vertically centered, to the top-left, with Gravity:
text.setGravity(Gravity.NO_GRAVITY);
Or set it by default for all LinedEditTexts:
public LinedEditTexts(Context context) {
super(context);
setGravity(Gravity.NO_GRAVITY); // or Gravity.TOP | Gravity.LEFT
...
}
Related
I am using Lined EditText to show vertical lines in an android app like notepad. When I add data it is displayed successfully but as data grows bottom lines disappear.
Any help will be appreciated.
Code:
public class LinedEditText extends AppCompatEditText {
private Rect mRect;
private Paint mPaint;
public LinedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(0xFF000000);
}
/**
* This is called to draw the LinedEditText object
*
* #param canvas The canvas on which the background is drawn.
*/
#Override
protected void onDraw(Canvas canvas) {
int height = canvas.getHeight();
int curHeight = 0;
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);
for (curHeight = baseline + 1; curHeight < height;
curHeight += getLineHeight()) {
canvas.drawLine(r.left, curHeight, r.right, curHeight, paint);
}
super.onDraw(canvas);
}
}
layout_file.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.g26app.LinedEditText
android:id="#+id/note"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"
android:gravity="top"
android:textSize="22sp" />
</LinearLayout>
This is the code you need based on max4ever
#Override
protected void onDraw(Canvas canvas) {
int height = getHeight();
int line_height = getLineHeight();
int count = height / line_height;
if (getLineCount() > count)
count = getLineCount();//for long text with scrolling
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);//first line
for (int i = 0; i < count; i++) {
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
baseline += getLineHeight();//next line
}
super.onDraw(canvas);
}
I updated onDraw of LinedEditText and it is working fine:
public void onDraw(Canvas canvas) {
int height = getHeight() / getLineHeight();
if (getLineCount() > height) {
height = getLineCount();
}
Rect rect = this.mRect;
Paint paint = this.mPaint;
int lineBounds = getLineBounds(0, rect);
for (int i = 0; i < height; i++) {
float f = (float) (lineBounds + 1);
canvas.drawLine((float) rect.left, f, (float) rect.right, f, paint);
lineBounds += getLineHeight();
}
super.onDraw(canvas);
}
Excluding word wrapped lines?
What I want to do is have a class that extends EditText draw line numbers to the left of each line. On it's face this is quite simple by iterating lines 0 through super.getLineCount() and drawing an index at the start of a line.
But what I'm not seeing a simple say to do; skip over lines that are wrapped (lines that don't end with a \n). For instance in vim it would like:
What I'm using to do the above scenario (line count not skipping wrapped lines)
protected void onDraw(Canvas canvas) {
...
int count = getLineCount();
for (int i = 0; i < count; ++i) {
getLineBounds(i, mRect);
String num = String.valueOf(i + 1);
mPaint.getTextBounds(num, 0, num.length(), mNumberRect);
canvas.drawText(num, NUMBER_LEFT_PAD, mRect.top + mTextHeight - 5, mPaint);
}
...
super.onDraw(canvas);
}
How would I detect which lines are word wrapped lines and which are line-broken lines?
Going off what Mike said, you can accomplish this by checking each rendered line to see if it's an actual line (preceded by a line break \n) or a word-wrapped line and only incrementing/drawing line numbers if it's an actual line.
protected void onDraw(Canvas canvas) {
int count = getLineCount();
int lineNumber = 1;
for (int i = 0; i < count; ++i) {
getLineBounds(i, mRect);
String num = String.valueOf(i + 1);
mPaint.getTextBounds(num, 0, num.length(), mNumberRect);
if (i == 0) {
canvas.drawText(num, NUMBER_LEFT_PAD, mRect.top + mTextHeight - 5, mPaint);
++lineNumber;
} else if (getText().charAt(getLayout().getLineStart(i) - 1) == '\n') {
canvas.drawText(num, NUMBER_LEFT_PAD, mRect.top + mTextHeight - 5, mPaint);
++lineNumber;
}
}
super.onDraw(canvas);
}
Improvising the code in #Lrdwhyt answer, I implemented subclass of EditText like this. It also sets left padding of EditText according to the line number text width.
public class LineNumberedEditText extends EditText
{
private final Context context;
private Rect rect;
private Paint paint;
public LineNumberedEditText(Context context)
{
super(context);
this.context = context;
init();
}
public LineNumberedEditText(Context context, AttributeSet attrs)
{
super(context, attrs);
this.context = context;
init();
}
public LineNumberedEditText(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
this.context=context;
init();
}
private void init()
{
rect = new Rect();
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.GRAY);
paint.setTextSize(20);
paint.setTypeface(Typeface.MONOSPACE);
}
#Override
protected void onDraw(Canvas canvas) {
int baseline;
int lineCount = getLineCount();
int lineNumber = 1;
for (int i = 0; i < lineCount; ++i)
{
baseline=getLineBounds(i, null);
if (i == 0)
{
canvas.drawText(""+lineNumber, rect.left, baseline, paint);
++lineNumber;
}
else if (getText().charAt(getLayout().getLineStart(i) - 1) == '\n')
{
canvas.drawText(""+lineNumber, rect.left, baseline, paint);
++lineNumber;
}
}
// for setting edittext start padding
if(lineCount<100)
{
setPadding(40,getPaddingTop(),getPaddingRight(),getPaddingBottom());
}
else if(lineCount>99 && lineCount<1000)
{
setPadding(50,getPaddingTop(),getPaddingRight(),getPaddingBottom());
}
else if(lineCount>999 && lineCount<10000)
{
setPadding(60,getPaddingTop(),getPaddingRight(),getPaddingBottom());
}
else if(lineCount>9999 && lineCount<100000)
{
setPadding(70,getPaddingTop(),getPaddingRight(),getPaddingBottom());
}
super.onDraw(canvas);
}
}
I recommend it.(draw line numbers in edittext)
#Override
protected void onDraw(Canvas canvas) {
int baseline = getBaseline()
for (int i = 0; i < getLineCount(); i++) {
canvas.drawText("" + (i+1), rect.left, baseline, paint);
baseline += getLineHeight();
}
super.onDraw(canvas);
}
I have a project in which I am trying to draw rectangles to fill the screen
MainActivity.java
public class MainActivity extends Activity {
private int vScreenHeight, vScreenWidth;
private int vLeftPos = 0;
private int vTopPos = 0;
private int vRightPos = 154;
private int vBottomPos = 154;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vGetScreenHeightAndWidth();
while(vTopPos < vScreenHeight) {
while(vLeftPos < vScreenWidth) {
RectView rectView = new RectView(getApplicationContext(), vLeftPos, vTopPos, vRightPos, vBottomPos);
vLeftPos += 154;
vRightPos += 154;
setContentView(rectView);
}
vLeftPos = 0;
vTopPos += 154;
vRightPos = 154;
vBottomPos += 154;
}
}
private void vGetScreenHeightAndWidth() {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size); // this will work only in API level 13 above.
vScreenWidth = size.x;
vScreenHeight = size.y;
}
}
RectView.java
public class RectView extends View implements OnClickListener
{
private int vLeftPos;
private int vTopPos;
private int vRightPos;
private int vBottomPos;
Rect r;
private Paint paint = new Paint();
private final String TAG = "Canvas Application";
public RectView(Context pAppContext, int pLeftPos, int pTopPos, int pRightPos, int pBottomPos)
{
super(pAppContext);
vLeftPos = pLeftPos;
vTopPos = pTopPos;
vRightPos = pRightPos;
vBottomPos = pBottomPos;
r = new Rect();
this.setOnClickListener(this);
}
public void onDraw(Canvas pCanvasObj)
{
r.set(vLeftPos, vTopPos, vRightPos, vBottomPos);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
pCanvasObj.drawRect(r, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLACK);
pCanvasObj.drawRect(r, paint);
}
#Override
public void onClick(View v)
{
Toast.makeText(null, "tapped", Toast.LENGTH_SHORT).show();
}
}
In this Activity, I am calculating the positions of the rectangles and creating a RectView object to draw the rectangles.
I am not able to understand what am I doing wrong ?
The problem is in RectView. You can try this:
public class RectView extends View {
private RectF rect;
private Paint paint;
/**
* #param context
*/
public RectView(Context context) {
super(context);
paint=new Paint();
paint.setColor(Color.RED);
rect=new RectF();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
rect.set(0, 0, MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(rect, paint);
}
I was taking a look at the notepad sample in the android SDK see here: http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html
Thing is it only draws the current line the cursor is on e.g http://cdn2.staztic.com/screenshots/simple-notepad-app-al-1.jpg
But I'd like to display lines that fill up the screen e.g. http://www.itismyworld.info/wp-content/uploads/2010/03/AK-notebook.png
Any suggestions would be great. The relevent bit of code seems to be here:
protected void onDraw(Canvas canvas) {
// Gets the number of lines of text in the View.
int count = getLineCount();
// Gets the global Rect and Paint objects
Rect r = mRect;
Paint paint = mPaint;
/*
* Draws one line in the rectangle for every line of text in the EditText
*/
for (int i = 0; i < count; i++) {
// Gets the baseline coordinates for the current line of text
int baseline = getLineBounds(i, r);
/*
* Draws a line in the background from the left of the rectangle to the right,
* at a vertical position one dip below the baseline, using the "paint" object
* for details.
*/
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
}
// Finishes up by calling the parent method
super.onDraw(canvas);
}
This is the code, based on jkhouws1's suggestion and google's note editor
public class LinedEditText extends EditText {
private Rect mRect;
private Paint mPaint;
// we need this constructor for LayoutInflater
public LinedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(R.color.edit_note_line); //SET YOUR OWN COLOR HERE
}
#Override
protected void onDraw(Canvas canvas) {
//int count = getLineCount();
int height = getHeight();
int line_height = getLineHeight();
int count = height / line_height;
if (getLineCount() > count)
count = getLineCount();//for long text with scrolling
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);//first line
for (int i = 0; i < count; i++) {
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
baseline += getLineHeight();//next line
}
super.onDraw(canvas);
}
}
In Eclipse IDE press Ctrl+Shift+O to add all needed imports
I think this is what you need:
public class LinedEditText extends EditText {
private static Paint linePaint;
static {
linePaint = new Paint();
linePaint.setColor(Color.BLACK);
linePaint.setStyle(Style.STROKE);
}
public LinedEditText(Context context, AttributeSet attributes) {
super(context, attributes);
}
#Override
protected void onDraw(Canvas canvas) {
Rect bounds = new Rect();
int firstLineY = getLineBounds(0, bounds);
int lineHeight = getLineHeight();
int totalLines = Math.max(getLineCount(), getHeight() / lineHeight);
for (int i = 0; i < totalLines; i++) {
int lineY = firstLineY + i * lineHeight;
canvas.drawLine(bounds.left, lineY, bounds.right, lineY, linePaint);
}
super.onDraw(canvas);
}
}
maybe after that for loop, you draw estimated* additional lines.
getHeight() will return EditText's height in pixels
getLineHeight() will height of one standard line
so getHeight/getlineHeight-getCount will be number of lines left to draw.
you can't use getLineBounds, using the above functions you could calculate the position of the remaining lines to draw.
*Estimated since formatting of text could change the line height, but since there is no text in these lines yet that shouldnt be an issue. But for that same reason you should only draw the remaining lines, and not use this to draw all the lines.
<com.example.goh2.pronoornotepad.LinedEditText
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffcc4b"
android:gravity="top|left"
android:singleLine="false"
android:text=""
/>
The above XML works with the code from Max4ever's answer:
public class LinedEditText extends EditText {
private Rect mRect;
private Paint mPaint;
// we need this constructor for LayoutInflater
public LinedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(R.color.edit_note_line); //SET YOUR OWN COLOR HERE
}
#Override
protected void onDraw(Canvas canvas) {
//int count = getLineCount();
int height = getHeight();
int line_height = getLineHeight();
int count = height / line_height;
if (getLineCount() > count)
count = getLineCount();//for long text with scrolling
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);//first line
for (int i = 0; i < count; i++) {
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
baseline += getLineHeight();//next line
}
super.onDraw(canvas);
}
}
I have problem with refreching canvas in my widget. I create custom widget and I want to repaint first cell on click.
There ins activity
public class TestView extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ElementView ev = (ElementView)findViewById(R.id.surface2);
ev.setOnClickListener(evOnClick);
}
public OnClickListener evOnClick = new OnClickListener() {
#Override
public void onClick(View v) {
ElementView temp=(ElementView)v;
temp.paint.setColor(Color.RED);
temp.canvas.drawRect(new Rect(0,0,90,90),temp.paint);
temp.postInvalidate();
}
};
}
and there is ElementView ( widget which I want to repaint )
public class ElementView extends View {
private final int width=100;
private final int height=100;
public Paint paint=null;
public Canvas canvas=null;
public ElementView(Context context) {
super(context);
paint = new Paint();
}
public ElementView(Context context, AttributeSet attr) {
super(context, attr);
paint = new Paint();
}
public ElementView(Context context, AttributeSet attr, int defaultStyles) {
super(context, attr, defaultStyles);
paint = new Paint();
}
#Override
protected void onMeasure(int widthSpec, int heightSpec) {
int measuredWidth = MeasureSpec.getSize(widthSpec);
int measuredHeight = MeasureSpec.getSize(heightSpec);
setMeasuredDimension(this.width,this.height);
}
#Override
protected void onDraw(Canvas canvas) {
this.canvas=canvas;
// get the size of your control based on last call to onMeasure
int height = getMeasuredHeight();
int width = getMeasuredWidth();
// Now create a paint brush to draw your widget
paint.setColor(Color.GREEN);
//define border
this.canvas.drawLine(0, 0, 0, 99, paint);
this.canvas.drawLine(0, 0, 99,0, paint);
this.canvas.drawLine(99, 0, 99, 99, paint);
this.canvas.drawLine(0, 99, 99,99, paint);
//define cells
this.canvas.drawLine(0,50,99,50,paint);
this.canvas.drawLine(30,0,30,50,paint);
//draw green rectangle
this.canvas.drawRect(new Rect(0,0,50,50),paint);
//draw some text
paint.setTextSize(8);
paint.setColor(Color.RED);
String displayText = "test";
Float textWidth = paint.measureText(displayText);
int px = width / 2;
int py = height / 2;
this.canvas.drawText(displayText, px - textWidth / 2, py, paint);
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
paint.setColor(Color.RED);
//change color of first cell
canvas.drawRect(new Rect(0,0,50,50),paint);
return super.dispatchTouchEvent(event);
}
}
When I click on ElementView it enter in Activity in onClick and pass through code without mistake or exception , but doesn't change view . Can anybody tell me where is mistake ?
I don't think writing to the Canvas outside of the onDraw method will have any effect on the screen.
Try setting a flag in your onClick method that you read in onDraw which will trigger your drawing routine.