Skip to content

Fixed #245: different padding between lines #315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 51 additions & 25 deletions library/src/main/java/com/tokenautocomplete/ViewSpan.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.style.ReplacementSpan;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -12,56 +14,80 @@
*
* Created on 2/3/15.
* @author mgod
*
* Updated on 15/04/2017
* Aleksandr Borisenko
*/
public class ViewSpan extends ReplacementSpan {

private static final String TAG = ViewSpan.class.getSimpleName();

private static final char SENTINEL = ',';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really comfortable adding a dependency on how the overall view is configured here. SENTINEL matches the default implementation, but breaks in some common cases like hashtags depending on configuration.


protected View view;
private int maxWidth;
private boolean prepared;

public ViewSpan(View v, int maxWidth) {
public ViewSpan(View view, int maxWidth) {
super();
this.maxWidth = maxWidth;
view = v;
view.setLayoutParams(new ViewGroup.LayoutParams(
this.view = view;
this.view.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
prepared = false;
}

private void prepView() {
int widthSpec = View.MeasureSpec.makeMeasureSpec(maxWidth, View.MeasureSpec.AT_MOST);
int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
if (!prepared) {
int widthSpec = View.MeasureSpec.makeMeasureSpec(maxWidth, View.MeasureSpec.AT_MOST);
int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);

view.measure(widthSpec, heightSpec);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.measure(widthSpec, heightSpec);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
prepared = true;
}
}

public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end,
float x, int top, int y, int bottom, @NonNull Paint paint) {
public int getHeight() {
prepView();
return view.getHeight();
}

@Override
public void draw(
@NonNull Canvas canvas, CharSequence text,
@IntRange(from = 0) int start, @IntRange(from = 0) int end,
float x, int top, int y, int bottom, @NonNull Paint paint) {
prepView();
canvas.save();
//Centering the token looks like a better strategy that aligning the bottom
int padding = (bottom - top - view.getBottom()) / 2;
canvas.translate(x, bottom - view.getBottom() - padding);
canvas.translate(x, top);
view.draw(canvas);
canvas.restore();
}

public int getSize(@NonNull Paint paint, CharSequence charSequence, int i, int i2, Paint.FontMetricsInt fm) {
@Override
public int getSize(
@NonNull Paint paint, CharSequence text,
@IntRange(from = 0) int start, @IntRange(from = 0) int end,
@Nullable Paint.FontMetricsInt fm) {
prepView();

// NOTE: only the first tag (measure) has ~2dp "padding"
// NOTE: a string with the single tag can be trimmed up to span height when the layout is inflated
String str = text.toString();
str = str.substring(0, str.lastIndexOf(SENTINEL) + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect rather than using a SENTINEL here, you can probably search for spans in the text and use that to figure out if there are mote.

if (start == 0 && str.length() > end) {
// WORKAROUND: first measure is ignored if there are other ones
return view.getRight();
}
if (fm != null) {
//We need to make sure the layout allots enough space for the view
int height = view.getMeasuredHeight();
int need = height - (fm.descent - fm.ascent);
if (need > 0) {
int ascent = need / 2;
//This makes sure the text drawing area will be tall enough for the view
fm.descent += need - ascent;
fm.ascent -= ascent;
fm.bottom += need - ascent;
fm.top -= need / 2;
final int height = view.getMeasuredHeight();
final int top_need = height - (fm.bottom - fm.top);
if (top_need != 0) {
int top_patch = top_need / 2;
fm.ascent = (fm.top -= top_patch);
fm.descent = (fm.bottom += top_need - top_patch);
}
}

return view.getRight();
}
}