How to exactly do Read More in an Android TextView? - android

Question: How to fade out the end of the last line and append Read More text in a TextView?
See:
Like in this post, I want to append read more text when description is about end and also you can notice that some text are blurry, invisible. I want all those.
I tried some answer, but that are different.
I want like this and at the end I want to append "Read More":
And I know there is answer in this question:
How to fade out the end of the last line in a TextView?
But that answer is not working for me.
My purpose is to not expand the texview while clicking on Read More, but instead I'll open new activity.

There was some problems this answer. I changed it a little bit as like this:
public class FadingTextView extends android.support.v7.widget.AppCompatTextView {
private static final double FADE_LENGTH_FACTOR = 1.5;
private final Shader shader;
private final Matrix matrix;
private final Paint paint;
private final Rect bounds;
public FadingTextView(Context context) {
this(context, null);
}
public FadingTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
public FadingTextView(Context context, AttributeSet attrs, int defStyleAttribute) {
super(context, attrs, defStyleAttribute);
matrix = new Matrix();
paint = new Paint();
bounds = new Rect();
shader = new LinearGradient(0f, 0f, 1f, 0f, 0, 0xFF000000, Shader.TileMode.CLAMP);
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
#Override
protected void onDraw(Canvas canvas) {
// Locals
final Matrix m = matrix;
final Rect b = bounds;
final Layout l = getLayout();
// Last line index
final int line = getLineCount() - 1;
// Determine text direction
final boolean isRtl = l.getParagraphDirection(line) == Layout.DIR_RIGHT_TO_LEFT;
// Last line bounds
getLineBounds(line, b);
// Adjust end bound to text length
final int lineStart = l.getLineStart(line);
final int lineEnd = l.getLineEnd(line);
final CharSequence text = getText().subSequence(lineStart, lineEnd);
final int measure = (int) (getPaint().measureText(text, 0, text.length()) + .5f);
final int fadeLength = (int) (b.width() / FADE_LENGTH_FACTOR);
// Save the layer
final int saveCount = canvas.saveLayer(b.left, 0, b.right,
b.bottom, null,
Canvas.ALL_SAVE_FLAG);
// Let TextView draw itself
super.onDraw(canvas);
// Adjust and set the Shader Matrix
m.reset();
m.setScale(fadeLength, 1f);
if (isRtl) {
m.postRotate(180f, fadeLength / 2f, 0f);
}
m.postTranslate(b.left, 0f);
shader.setLocalMatrix(matrix);
// Finally draw the fade
canvas.drawRect(b, paint);
canvas.restoreToCount(saveCount);
}
}
TextView
<com.example.FadingTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#e2f3eb"
android:ellipsize="end"
android:maxLines="3"
android:text="Lorem ipsum dolor....."
android:textColor="#0b8043" />
Read More:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="#+id/post_desc"
android:layout_alignBottom="#+id/post_desc"
android:layout_marginEnd="0dp"
android:layout_marginBottom="0dp"
android:background="#android:color/transparent"
android:text="Read More"/>
FADE_LENGTH_FACTOR = 1
FADE_LENGTH_FACTOR = 1.5

Related

How to apply horizontal fading edge on the last line of a maxLine TextView

I'd like to implement a fading edge behavior to TextView like the Google Play Movie does:
As you can see the last letters of the third line have a fading edge effect.
Is there a way to achieve this for a specific line defined via android:maxLines? (For example android:maxLines="3")
I've tried the following but it works with the attribute android:singleLine only which is not my goal:
<TextView
...
android:requiresFadingEdge="horizontal"
android:fadingEdgeLength="30dp"
android:ellipsize="none"
android:singleLine="true" />
Setting android:maxLines here instead results in no fading at all.
Edit/Additional:
Previously I also tried a Shader with LinearGradient while extending TextView like here, but the described solution applies a background/foreground (and there were also some other issues with it ...).
I'd like to apply the Gradient to the last 3-4 characters of the maxLine line. Could this be possible?
Edit:
With Mike M.'s help (take a look into the comments) I could modify his answer to reach my wanted behavior. The final implementation with additions (or here as java file):
public class FadingTextView extends AppCompatTextView {
// Length
private static final float PERCENTAGE = .9f;
private static final int CHARACTERS = 6;
// Attribute for ObjectAnimator
private static final String MAX_HEIGHT_ATTR = "maxHeight";
private final Shader shader;
private final Matrix matrix;
private final Paint paint;
private final Rect bounds;
private int mMaxLines;
private boolean mExpanded = false;
public FadingTextView(Context context) {
this(context, null);
}
public FadingTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
public FadingTextView(Context context, AttributeSet attrs, int defStyleAttribute) {
super(context, attrs, defStyleAttribute);
matrix = new Matrix();
paint = new Paint();
bounds = new Rect();
shader = new LinearGradient(0f, 0f, PERCENTAGE, 0f, Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP);
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
mMaxLines = getMaxLines();
}
#Override
protected void onDraw(Canvas canvas) {
if (getLineCount() > getMaxLines() && !mExpanded
&& getRootView() != null && getText() != null
) {
final Matrix m = matrix;
final Rect b = bounds;
final Layout l = getLayout();
int fadeLength = (int) (getPaint().measureText(getText(), getText().length() - CHARACTERS, getText().length()));
final int line = mMaxLines - 1;
getLineBounds(line, b);
final int lineStart = l.getLineStart(line);
final int lineEnd = l.getLineEnd(line);
final CharSequence text = getText().subSequence(lineStart, lineEnd);
final int measure = (int) (getPaint().measureText(text, 0, text.length()));
b.right = b.left + measure;
b.left = b.right - fadeLength;
final int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null);
super.onDraw(canvas);
m.reset();
m.setScale(fadeLength, 1f);
m.postTranslate(b.left, 0f);
shader.setLocalMatrix(matrix);
canvas.drawRect(b, paint);
canvas.restoreToCount(saveCount);
} else {
super.onDraw(canvas);
}
}
/**
* Makes the TextView expanding without any animation.
*/
public void expandCollapse() {
setMaxLines(mExpanded ? mMaxLines : getLineCount());
mExpanded = !mExpanded;
}
/**
* Makes the TextView expanding/collapsing with sliding animation (vertically)
*
* #param duration Duration in milliseconds from beginning to end of the animation
*/
public void expandCollapseAnimated(final int duration) {
// Height before the animation (either maxLine or lineCount, depending on current state)
final int startHeight = getMeasuredHeight();
// Set new maxLine value depending on current state
setMaxLines(mExpanded ? mMaxLines : getLineCount());
mExpanded = !mExpanded;
// Measuring new height
measure(View.MeasureSpec.makeMeasureSpec(
getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
);
final int endHeight = getMeasuredHeight();
ObjectAnimator animation = ObjectAnimator.ofInt(
this, // TextView
MAX_HEIGHT_ATTR, // maxHeight
startHeight, // height before animation
endHeight // height after animation
);
animation.setDuration(duration).start();
}
/**
* Sets maxLine value programmatically
*
* #param newValue new value for maxLines
*/
public void setNewMaxLine(int newValue) {
mMaxLines = newValue;
}
}
Try this out .. Hope this will work
public class ShadowSpan : Android.Text.Style.CharacterStyle
{
public float Dx;
public float Dy;
public float Radius;
public Android.Graphics.Color Color;
public ShadowSpan(float radius, float dx, float dy, Android.Graphics.Color color)
{
Radius = radius; Dx = dx; Dy = dy; Color = color;
}
public override void UpdateDrawState (TextPaint tp)
{
tp.SetShadowLayer(Radius, Dx, Dy, Color);
}
}

How to show Text on CustomTextView in multi-line

it tried and use CustomTextView but all text show in single line. i want to show text in multi lines.
here my code
<com.textdesign.views.CustomTextView
android:id="#+id/customTextview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:singleLine="false"
android:inputType="textMultiLine"
android:maxLines="40"
android:lines="20"
android:minLines="5"
android:text="this is sample text for multi-lines\nthis is sample text for multi-lines\nthis is sample text for multi-lines\nthis is sample text for multi-lines"
android:textStyle="bold" />
I used minLines, maxLines, singleLine="false", inputType="textMultiLine" but still show like this:
here my CustomTextView class i have hide some of my code this code also show text in single line.
public class CustomTextView extends AppCompatTextView {
//Shadow Variable
public static int shadow_length = 30;
public int x_direction = 1;
public int y_direction = 1;
boolean shadow_Enable = false;
int color = Color.BLACK;
float[] hsv = new float[]{0, 0, 0};
int getcol;
Paint paint;
Paint paint1;
Paint paint2;
public CustomTextView(Context context, AttributeSet attributeSet) {
super(context, attributeSet,android.R.attr.textViewStyle);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(getTextSize());
}
#Override
protected void onDraw(Canvas canvas) {
getPaint().setMaskFilter(null);
TextPaint textPaint = getPaint();
float x_position = (getWidth() - getPaint().measureText(getText().toString())) / 2f;
float y_position = (int) ((getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2));
getPaint().setColor(shadowColor);
//Center point for transformation
PointF center_Point = new PointF(getWidth() / 2f, getHeight() / 2f);
Camera camera = new Camera();
canvas.drawText(getText().toString(), x_position, y_position, getPaint());
}
}
Use
android:maxLength="10"
As per the length requirement
along with max lines
i just remove x_position and y_position,
#Override
protected void onDraw(Canvas canvas) {
//.........
StaticLayout mTextLayout = new StaticLayout(getText().toString(), getPaint(), canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
canvas.save();
float textHeight = getTextHeight(getText().toString(), textPaint);
int numberOfTextLines = mTextLayout.getLineCount();
float textYCoordinate = mTextBounds.exactCenterY() - ((numberOfTextLines * textHeight) / 2);
// text will be drawn from left
float textXCoordinate = mTextBounds.left;
canvas.translate(0, 0);
// draws static layout on canvas
mTextLayout.draw(canvas);
canvas.restore();
//.....
}

Programatically spread drawn markers around a drawn arc in Android Java

I am having a hard time dealing with this issue, most of the "help" i have found deals with Trigonometry, which is something I have no experience with. I need to create a view like this: Proposed Graphics.
I have the arc and and the background image of the main gauge but I need to add the time markers you see, both the oval like shapes and the times. They need to be added programmatically because the number of markers can be from 1 to 28, though probably not more than 10.
I have tried using the sweep angle to get the X/Y position of the where the arc ends (using division to define an increasing sweep angle to increment the arc) and it sort of worked for the first one but I could not replicate it for any other one with a different sweep angle.
I am also using a matrix to rotate the marker image which is more or less working, I have been trying various trig functions to get the x and y. Below is some code:
Basic code:
public class Custom_clock extends View
{
private Paint mPaint;
private RectF rectF;
private int mStrokeWidth;
private int width;
private int height;
private Typeface custom_font;
private final int MAX = 263;
private final int START = 138;
private Bitmap bitmap;
private Bitmap marker;
private int scaledSizeNumbers;
private int scaledSizeLabels;
private int scaledSizeDose;
private Matrix matrix = new Matrix();
private String hoursMinsLabel = "Minutes";
private String hoursMinsNumber = "3";
private ArrayList<String>DoseTimes = new ArrayList<>();
public Custom_clock(Context context)
{
super(context);
}
public Custom_clock(Context context, AttributeSet attrs) {
super(context, attrs);
}
public Custom_clock(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private void initClock(){
width = getWidth();
height = getHeight();
mStrokeWidth = ((width+height)/33);
custom_font = Typeface.createFromAsset(getResources().getAssets(), "fonts/text_font.ttf");
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.base_arc3);
marker = BitmapFactory.decodeResource(getResources(), R.drawable.single_marker);
scaledSizeNumbers = getResources().getDimensionPixelSize(R.dimen.NumberFontSize);
scaledSizeLabels = getResources().getDimensionPixelSize(R.dimen.LabelFontSize);
scaledSizeDose = getResources().getDimensionPixelSize(R.dimen.DoseFontSize);
int scaledMarginWidth = getResources().getDimensionPixelSize(R.dimen.WidthMargin);
int scaledMarginTop = getResources().getDimensionPixelSize(R.dimen.TopMargin);
mPaint = new Paint();
rectF = new RectF(scaledMarginWidth,scaledMarginTop,getWidth()- scaledMarginWidth,getHeight());
DoseTimes.clear();
DoseTimes.add("1:00pm");
DoseTimes.add("2:00pm");
DoseTimes.add("3:00pm");
DoseTimes.add("4:00pm");
DoseTimes.add("5:00pm");
}
private void DrawMainArc(Canvas canvas){
Paint paint =new Paint();
initClock();
canvas.drawBitmap(bitmap,null,rectF,paint);
mPaint.setColor(getResources().getColor(R.color.light_grey));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth+2);
mPaint.setStrokeCap(Paint.Cap.ROUND);
canvas.drawArc(rectF,START,GetStops(5,MAX)*2,false, mPaint);
}
private int GetStops(int stops, int max){
return max/stops;
}
#Override
protected void onDraw(Canvas canvas)
{
if(bitmap != null){
super.onDraw(canvas);
DrawMainArc(canvas);
DrawOutlineArc(canvas);
DrawHours(canvas);
DrawHoursLabel(canvas);
DrawDoseLabel(canvas);
AddStops(canvas);
}
}
Marker specific code attempt:
This draws the first marker fairly close to where I want it but the rest are drawn up and to the left increasingly, only 2 are even visible. I know the answer lies somewhere with the angle and possibly a matrix but trig > me.
private void AddStops(Canvas canvas){
int stopsNum = DoseTimes.size();//currently 5
int rotatinalIncrement = MAX/(stopsNum);//currently 54
int markerAngle = 0;
double x;
double y;
for(int i =0; i <stopsNum; i++){
x = (canvas.getWidth()/4) * Math.cos(markerAngle);
y = (canvas.getWidth()/4) * Math.cos(markerAngle);
markerAngle = markerAngle +rotatinalIncrement;
DrawMarker(canvas,markerAngle,(int)x ,(int)y);
}
}
private void DrawMarker(Canvas canvas, int Angle, int x, int y){
int scaledSize = getResources().getDimensionPixelSize(R.dimen.MarkerSize);
Bitmap scaled = Bitmap.createScaledBitmap(marker,scaledSize,scaledSize,false);
matrix.reset();
matrix.postTranslate(-canvas.getWidth() / 2, -canvas.getHeight() / 2); // Centers image
matrix.postRotate(angle);
matrix.setRotate(Angle);
matrix.postTranslate(x, y);
canvas.drawBitmap(scaled, matrix, null);
}
At first, Math.cos and sin use argument in radians, while you (as seems from value 54) apply argument in degrees. Just make markerAngle * Math.Pi / 180 or use function like toRadians if it exists in JavaScript.
Second - for y-coordinate you have to use sin rather than cos

Draw round corners on top left top right bottom left bottom right using Path and RectF in Android

By making a custom ImageView and override the onDraw method with the following will make the ImageView to have rounded corners. Reference
#Override
protected void onDraw(Canvas canvas) {
float radius = getContext().getResources().getDimension(R.dimen.round_corner_radius);
Path path = new Path();
RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight());
path.addRoundRect(rect, radius, radius, Path.Direction.CW);
canvas.clipPath(path);
super.onDraw(canvas);
}
How can I selectively make the round corners instead of making all four corners round. For example, only making the top left and top right corners round and leave the bottom corners intact. Here is a solution to do to through Bitmap. I am looking for doing it in this onDraw method and only using Path and RectF.
There is a Path#addRoundRect() overload that takes a float array of eight values wherein we can specify the x- and y-radius for each of the four corners. These values are in [x, y] pairs, starting at the top-left corner, and going clockwise around the rest. For those corners we want rounded, we set both values of the pair to the radius value, and leave them at zero for those we don't.
As an illustrative example, a simple method that will return a Path that can be used in your snippet:
private Path getPath(float radius, boolean topLeft, boolean topRight,
boolean bottomRight, boolean bottomLeft) {
final Path path = new Path();
final float[] radii = new float[8];
if (topLeft) {
radii[0] = radius;
radii[1] = radius;
}
if (topRight) {
radii[2] = radius;
radii[3] = radius;
}
if (bottomRight) {
radii[4] = radius;
radii[5] = radius;
}
if (bottomLeft) {
radii[6] = radius;
radii[7] = radius;
}
path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()),
radii, Path.Direction.CW);
return path;
}
Per your example description, rounding the top-left and top-right corners:
#Override
protected void onDraw(Canvas canvas) {
float radius = getContext().getResources().getDimension(R.dimen.round_corner_radius);
Path path = getPath(radius, true, true, false, false);
canvas.clipPath(path);
super.onDraw(canvas);
}
As always, I would recommend keeping the onDraw() method as tight as possible, moving anything that doesn't absolutely have to be there elsewhere. The resource value for the radius, for instance, could be retrieved in the constructor, and kept in a field. Furthermore, the Path could be constructed only when necessary; i.e., when the View's size changes, or when the radius or chosen corners change.
Since I put together a simple custom ImageView to test this, I'll include it here, as it demonstrates the above points. This custom View also offers XML attributes that allow the corner radius and the rounded corners to be set in your layout.
public class RoundishImageView extends ImageView {
public static final int CORNER_NONE = 0;
public static final int CORNER_TOP_LEFT = 1;
public static final int CORNER_TOP_RIGHT = 2;
public static final int CORNER_BOTTOM_RIGHT = 4;
public static final int CORNER_BOTTOM_LEFT = 8;
public static final int CORNER_ALL = 15;
private static final int[] CORNERS = {CORNER_TOP_LEFT,
CORNER_TOP_RIGHT,
CORNER_BOTTOM_RIGHT,
CORNER_BOTTOM_LEFT};
private final Path path = new Path();
private int cornerRadius;
private int roundedCorners;
public RoundishImageView(Context context) {
this(context, null);
}
public RoundishImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundishImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundishImageView);
cornerRadius = a.getDimensionPixelSize(R.styleable.RoundishImageView_cornerRadius, 0);
roundedCorners = a.getInt(R.styleable.RoundishImageView_roundedCorners, CORNER_NONE);
a.recycle();
}
public void setCornerRadius(int radius) {
if (cornerRadius != radius) {
cornerRadius = radius;
setPath();
invalidate();
}
}
public int getCornerRadius() {
return cornerRadius;
}
public void setRoundedCorners(int corners) {
if (roundedCorners != corners) {
roundedCorners = corners;
setPath();
invalidate();
}
}
public boolean isCornerRounded(int corner) {
return (roundedCorners & corner) == corner;
}
#Override
protected void onDraw(Canvas canvas) {
if (!path.isEmpty()) {
canvas.clipPath(path);
}
super.onDraw(canvas);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setPath();
}
private void setPath() {
path.rewind();
if (cornerRadius >= 1f && roundedCorners != CORNER_NONE) {
final float[] radii = new float[8];
for (int i = 0; i < 4; i++) {
if (isCornerRounded(CORNERS[i])) {
radii[2 * i] = cornerRadius;
radii[2 * i + 1] = cornerRadius;
}
}
path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()),
radii, Path.Direction.CW);
}
}
}
For the XML attributes to work, the following needs to be in your <resources>, which you can do by putting this file in your project's res/values/ folder, or adding to the one that might already be there.
attrs.xml
<resources>
<declare-styleable name="RoundishImageView">
<attr name="cornerRadius" format="dimension" />
<attr name="roundedCorners">
<flag name="topLeft" value="1" />
<flag name="topRight" value="2" />
<flag name="bottomRight" value="4" />
<flag name="bottomLeft" value="8" />
<flag name="all" value="15" />
</attr>
</declare-styleable>
</resources>
The cornerRadius is a dimension attribute, and should be specified as a dp or px value. The roundedCorners is a flag attribute, and multiple corners can be chosen using the pipe character, |. For example:
<com.mycompany.myapp.RoundishImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/riv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:src="#drawable/magritte"
app:cornerRadius="#dimen/round_corner_radius"
app:roundedCorners="topLeft|topRight" />
I also spent a half-day to solve the problem; the key point here is how to use mPath.arcTo make a corner. The basic knowledge is E direction is 0 degree, then the second param means which degree start; the third param means how many degrees to show.
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
public class RectangleConerView extends View {
private Path mPath;
private Paint mPaint;
private PathMeasure mPathMeasure;
private float mAnimatorValue;
private Path mDst;
private float mLength;
private float left = 300;
private float top = 200;
private float width = 800;
private float height = 300;
private float checkWidth = 100;
private float checkHeight = 60;
private float cornerRadius = 30;
public RectangleConerView(Context context) {
super(context);
}
public RectangleConerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public RectangleConerView(Context context, AttributeSet attrs)
{
super(context, attrs);
mPathMeasure = new PathMeasure();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPath = new Path();
mPath.moveTo(left + width, top + checkHeight/2);
//bottom-right
mPath.lineTo(left + width, top + height - cornerRadius);
mPath.arcTo(new RectF(left + width-cornerRadius, top + height - cornerRadius, left + width, top + height), 0, 90); //start degree is E direct, then CW 90 degree, which is the bottom-right corner.
//bottom-left
mPath.lineTo(left + cornerRadius, top + height);
mPath.arcTo(new RectF(left, top + height - cornerRadius, left + cornerRadius, top + height), 90, 90);//start degree is the S, then CW 90 degree, which is the bottom-left corner.
//top-left
mPath.lineTo(left, top + cornerRadius);
mPath.arcTo(new RectF(left, top, left + cornerRadius, top + cornerRadius), 180, 90);//start degree W
//top-right
mPath.lineTo(left + width - checkWidth/2, top);
mPathMeasure.setPath(mPath, false);
mLength = mPathMeasure.getLength();
mDst = new Path();
final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mAnimatorValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator.setDuration(1000);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.start();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDst.reset();
// 硬件加速的BUG
mDst.lineTo(0,0);
float stop = mLength * mAnimatorValue;
mPathMeasure.getSegment(0, stop, mDst, true);
canvas.drawPath(mDst, mPaint);
}
}

How do I create horizontal lines in multiline edittext on each line using xml? [duplicate]

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);
}
}

Categories

Resources