Il existe de nombreuses expériences où vous essayez de faire en sorte que TextView affiche une longue chaîne dans une situation où seul un espace limité est disponible, et la chaîne est coupée au milieu et elle ne semble pas bonne. Il peut y avoir différentes solutions, mais pour l'instant, nous allons nous concentrer sur un attribut TextView appelé textScaleX. Il s'agit d'une valeur qui indique le rapport d'expansion / contraction horizontale du caractère à afficher. Si la valeur est supérieure à 1, la chaîne de caractères est développée et si elle est inférieure à 1, la chaîne de caractères est contractée. J'ai créé une vue qui ajuste automatiquement la valeur de ce textScaleX pour compresser la longueur de la chaîne lors de l'affichage d'une chaîne qui ne rentre pas dans la largeur maximale du TextView. Appelons également le nom de classe ExpandableTextView.
L'arrière-plan de ExpandableTextView est grisé pour plus de clarté.
Cas pour layout_width de LayoutParam. La valeur de android: layout_width qui est définie statiquement en XML.
Installez-le dans Github Je vais.
Confirmé avec la version SDK = 26
Je veux l'implémenter facilement, alors j'hérite de TextView et je joue avec. Comportement modifié en remplaçant certaines méthodes.
Fournit le contrôle pour développer ou réduire la chaîne de caractères ou la remplacer par une chaîne de caractères alternative selon les besoins pour la largeur maximale autorisée
ExpandableTextView#updateText
private Paint mTextPaint; //Objet pour dessiner des personnages
private CharSequence mDisplayedText //La chaîne de caractères réellement affichée
private void updateText(CharSequence text, BufferType type, int widthSize){
mTextPaint.setTextScaleX(1f);
float length = mTextPaint.measureText(text, 0, text.length());
int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
if ( length + padding > widthSize ){
float scale = (widthSize - padding) / length;
text = modifyText(scale, text, widthSize - padding);
}
mDisplayedText = text;
super.setText(text, type);
}
/**
*Réduit la chaîne horizontalement pour l'adapter à la largeur maximale spécifiée.
*Taux de rétrécissement{@link #mMinTextScaleX}S'il est inférieur à, remplacez-le par une chaîne de caractères alternative qui correspond à la largeur maximale au rapport minimum.
* @param scale rough value, with which text width can be adjusted to maxLength
* @param text raw text
* @param maxLength max length of text
* @return modified text
*/
private CharSequence modifyText(float scale, CharSequence text, float maxLength){
//Référence du code source
}
Plus précisément, modifyText () est utilisé pour réduire la chaîne de caractères ou la remplacer par une autre chaîne de caractères. Notez que la longueur de la chaîne mesurée par Paint # measureText est
Par conséquent, afin de rechercher le grossissement souhaité textScaleX, le grossissement est modifié petit à petit avec un coup approprié et la meilleure valeur est adoptée. De même, afin de déterminer une chaîne de caractères alternative qui correspond à la chaîne de caractères dans la largeur maximale, il est devenu une méthode de mise en œuvre décevante de recherche tout en grattant de la fin un caractère à la fois. Le code est sale donc je ne le mettrai pas ici.
Cette méthode est appelée pour mesurer la taille de cette vue lorsqu'elle est placée par la vue parent. Pour plus d'informations sur le rôle de onMeasure (), voir [Qiita] Understanding onMeasure and onLayout. Cette fois, je ne suis intéressé que par la largeur, je vais donc ajouter une requête à measureSpec pour la largeur. Puisqu'il est difficile d'implémenter tout onMeasure () par vous-même, passez-le à super # onMeasure () tel quel à l'exception de la largeur et lancez-le à la classe parente.
ExpandableTextView#onMeasure
private Paint mTextPaint; //Objet pour dessiner des personnages
private CharSequence mCurrentText; //La chaîne de caractères que vous souhaitez afficher
private CharSequence mDisplayedText;//La chaîne de caractères réellement affichée
private int mMaxWidth; //Largeur maximum
private int mRawWidthMeasureSpec; //Demande de la taille de cette vue spécifiée par le parent
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
//Ajouter une demande uniquement pour la largeur
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
CharSequence text = mCurrentText;
mTextPaint.setTextScaleX(1f);
float length = mTextPaint.measureText(text, 0, text.length());
int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
int requestedWidth = 0;
switch ( widthMode ){
case MeasureSpec.EXACTLY:
//Fixé à la largeur spécifiée quelle que soit la chaîne de caractères à afficher
requestedWidth = widthSize;
//Ajustez la chaîne de caractères affichée en fonction de la largeur fixe
updateText(mCurrentText, BufferType.NORMAL, widthSize);
break;
case MeasureSpec.AT_MOST:
int max = Math.min(widthSize, mMaxWidth);
if ( length + padding > max ){
//Compresser s'il ne rentre pas dans la largeur maximale
requestedWidth = max;
float scale = (max - padding) / length;
CharSequence modified = modifyText(scale, text, max - padding);
if ( !mDisplayedText.equals(modified) ){
mDisplayedText = modified;
super.setText(modified, BufferType.NORMAL);
}
}else{
//S'il convient, ajustez la largeur de la vue à la largeur de la chaîne de caractères
requestedWidth = (int)Math.ceil(length + padding);
}
break;
case MeasureSpec.UNSPECIFIED:
//Si non spécifié, décidez vous-même
requestedWidth = (int)Math.ceil(length + padding);
mTextPaint.setTextScaleX(1f);
mDisplayedText = text;
break;
}
mRawWidthMeasureSpec = widthMeasureSpec;
//Ajouter une demande car la largeur est fixe
int calcWidthMeasureSpec = MeasureSpec.makeMeasureSpec(requestedWidth, MeasureSpec.EXACTLY);
// onMeasure()Quitter la mise en œuvre détaillée de
super.onMeasure(calcWidthMeasureSpec, heightMeasureSpec);
}
L'implémentation doit se comporter comme prévu même lorsque la chaîne de caractères à afficher avec setText () change. Le point important ici est lorsque TextView appelle layout (). Si la taille d'un TextView normal dépend de son contenu (lorsque MeasureSpec.AT_MOST est spécifié par onMeasure (), par exemple en spécifiant wrap_content dans LayoutParam),
--La chaîne de caractères affichée par setText () change --SetMaxWidth () modifie la largeur maximale --textScaleX change avec setTextScaleX ()
Appelez layout () au moment de pour recalculer la taille de View. Cette fois en plus de ce qui précède
--setMinTextScaleX () modifie la valeur minimale de textScaleX
Implémentez pour que layout () soit appelé même au moment de.
Ce qui précède est le cas où la taille de la vue dépend du contenu. Si la largeur est spécifiée par MeasureSpec.EXACTEMENT à partir du parent, ajustez la chaîne de caractères et le rapport d'expansion / contraction affichés par updateText () en fonction de la largeur fixe.
ExpandableTextView
private CharSequence mCurrentText; //La chaîne de caractères que vous souhaitez afficher
private CharSequence mDisplayedText //La chaîne de caractères réellement affichée
private int mMaxWidth; //Largeur maximum
private int mRawWidthMeasureSpec; //Demande de la taille de cette vue spécifiée par le parent
private float mMinTextScaleX; //Valeur minimale de textScalex
@Override
public void setMaxWidth(int width){
// super#Puisque mMaxWidth est privé, enregistrez-le vous-même
if ( width <= 0 ) return;
if ( width != mMaxWidth ){
mMaxWidth = width;
mRequestMeasure = true;
super.setMaxWidth(width);
//maxWidth est un paramètre où la largeur de cette vue dépend du contenu (wrap)_Uniquement valable pour le contenu, etc.)
//Dans de tels cas, la classe parente est layout()Appel
}
}
/**
*Spécifiez la valeur minimale de l'échelle horizontale de la chaîne de caractères.
* @param scale in range of (0,1]
* @see TextPaint#setTextScaleX(float)
*/
public void setMinTextScaleX(float scale){
if ( scale <= 0 || scale > 1 ) return;
if ( mMinTextScaleX != scale ){
mMinTextScaleX = scale;
if ( MeasureSpec.getMode(mRawWidthMeasureSpec) == MeasureSpec.EXACTLY ){
// layout()Pas besoin de
updateText(mCurrentText, BufferType.NORMAL, MeasureSpec.getSize(mRawWidthMeasureSpec));
}else{
// layout()Et recalculez la taille
requestLayout();
}
}
}
//#setText(char[], int, int) <-Ne peut pas être remplacé en finale
//Autre que cela, c'est par ici
@Override
public void setText(CharSequence text, BufferType type){
if ( text == null ) return;
if ( mCurrentText != null && mCurrentText.equals(text) ) return;
mCurrentText = text;
if ( MeasureSpec.getMode(mRawWidthMeasureSpec) == MeasureSpec.EXACTLY ){
//La classe parent est la mise en page()Non, pas besoin de
updateText(text, type, MeasureSpec.getSize(mRawWidthMeasureSpec));
}else{
//La classe parent est la mise en page()Faire
super.setText(text, type);
}
}
Dans cette implémentation, setTextScaleX () est utilisé pour spécifier le rapport d'expansion / contraction de la chaîne de caractères de l'objet Paint utilisé pour dessiner des caractères obtenus par TextView # getPaint (). Il y a une note dans getPaint () que vous ne devez pas jouer avec les propriétés de Paint (original: [Utilisez ceci uniquement pour consulter les propriétés de Paint et ne pas les changer.](Https://developer.android.com/reference/android. /widget/TextView.html#getPaint ())), textScaleX a les points d'implémentation suivants.
TextView
public void setTextScaleX(float size) {
if (size != mTextPaint.getTextScaleX()) {
mUserSetTextScaleX = true;
mTextPaint.setTextScaleX(size);
if (mLayout != null) {
nullLayouts();
requestLayout();
invalidate();
}
}
}
private void setText(CharSequence text, BufferType type, boolean notifyBefore, int oldlen) {
/*Omission*/
if (!mUserSetTextScaleX) mTextPaint.setTextScaleX(1.0f);
/*Omission*/
}
Si vous ne spécifiez pas depuis setTextScaleX () de TextView, textScaleX = 1.0f écrasera ***! *** *** Je l'ai eu au début. Solution: appelez TextView # setTextScaleX () au moins une fois.
ExpandableTextView
public class ExpandableTextView extends AppCompatTextView{
public ExpandableTextView(Context context, AttributeSet attr, int defaultAttr){
super(context, attr, defaultAttr);
/*Omission*/
//Vous pouvez spécifier une valeur différente de la valeur actuelle, donc getTextScaleX() / 2f
super.setTextScaleX(getTextScaleX() / 2f);
}
Recommended Posts