web-dev-qa-db-fra.com

Définition d'une largeur maximale sur un ViewGroup

Comment définir la largeur maximale d'un ViewGroup? J'utilise un Theme.Dialog activité, cependant, cela ne semble pas si bon lorsqu'il est redimensionné sur des écrans plus grands, c'est aussi une sorte de légèreté et je ne veux pas qu'il occupe tout l'écran.

J'ai essayé cette suggestion en vain. De plus, il n'y a pas de Android:maxWidth propriété comme certaines vues.

Existe-t-il un moyen de restreindre le LinearLayout racine de sorte qu'il ne soit que (par exemple) 640 dip? Je suis prêt à passer à un autre ViewGroup pour cela.

Aucune suggestion?

58
zsniperx

Une option que j'ai faite est d'étendre LinearLayout et de remplacer la fonction onMeasure. Par exemple:

public class BoundedLinearLayout extends LinearLayout {

    private final int mBoundedWidth;

    private final int mBoundedHeight;

    public BoundedLinearLayout(Context context) {
        super(context);
        mBoundedWidth = 0;
        mBoundedHeight = 0;
    }

    public BoundedLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BoundedView);
        mBoundedWidth = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_width, 0);
        mBoundedHeight = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_height, 0);
        a.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Adjust width as necessary
        int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
        if(mBoundedWidth > 0 && mBoundedWidth < measuredWidth) {
            int measureMode = MeasureSpec.getMode(widthMeasureSpec);
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedWidth, measureMode);
        }
        // Adjust height as necessary
        int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
        if(mBoundedHeight > 0 && mBoundedHeight < measuredHeight) {
            int measureMode = MeasureSpec.getMode(heightMeasureSpec);
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedHeight, measureMode);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

Ensuite, vous XML utiliseriez la classe personnalisée:

<com.yourpackage.BoundedLinearLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content"
    Android:orientation="vertical"
    app:bounded_width="900dp">

    <TextView
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
    />
</com.youpackage.BoundedLinearLayout>

Et l'entrée du fichier attr.xml

<declare-styleable name="BoundedView">
    <attr name="bounded_width" format="dimension" />
    <attr name="bounded_height" format="dimension" />
</declare-styleable>

EDIT: Ceci est le code que j'utilise actuellement. Ce n'est pas encore terminé mais fonctionne dans la plupart des cas.

88
Chase

En s'appuyant sur la réponse originale de Chase (+1), j'apporterais quelques modifications (décrites ci-dessous).

  1. J'aurais la largeur maximale définie via un attribut personnalisé (xml sous le code)

  2. J'appellerais d'abord super.measure() puis ferais la comparaison Math.min(*). En utilisant le code de réponses d'origine, nous pouvons rencontrer des problèmes lorsque la taille entrante définie dans MeasureSpec est soit LayoutParams.WRAP_CONTENT Soit LayoutParams.FILL_PARENT. Comme ces constantes valides ont des valeurs de - 2 et - 1 respectivement, la Math.min(*) d'origine devient inutile car elle préservera ces valeurs sur la taille maximale, et dire que le WRAP_CONTENT mesuré est plus grand que notre taille maximale, ce chèque ne l'attraperait pas. J'imagine que l'OP ne pensait qu'aux dims exacts (pour lesquels cela fonctionne très bien)

    public class MaxWidthLinearLayout extends LinearLayout {
    
    private int mMaxWidth = Integer.MAX_VALUE;
    
    public MaxWidthLinearLayout(Context context) {
    
        super(context);
    }
    
    public MaxWidthLinearLayout(Context context, AttributeSet attrs) {
    
        super(context, attrs);
    
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaxWidthLinearLayout);
        mMaxWidth = a.getDimensionPixelSize(R.styleable.MaxWidthLinearLayout_maxWidth, Integer.MAX_VALUE);
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //get measured height
        if(getMeasuredWidth() > mMaxWidth){
            setMeasuredDimension(mMaxWidth, getMeasuredHeight());
        }
    }
    }
    

et le xml attr

    <!-- MaxWidthLinearLayout -->
    <declare-styleable name="MaxWidthLinearLayout">
        <attr name="maxWidth" format="dimension" />
    </declare-styleable>
29
Dori

Voici un meilleur code pour la réponse de Dori.

Dans la méthode onMeasure, Si vous appelez super.onMeasure(widthMeasureSpec, heightMeasureSpec); d'abord dans la méthode, la largeur de tous les objets dans la disposition ne sera pas modifiée. Parce qu'ils se sont initialisés avant de définir la largeur de la disposition (parent).

public class MaxWidthLinearLayout extends LinearLayout {
    private final int mMaxWidth;

    public MaxWidthLinearLayout(Context context) {
        super(context);
        mMaxWidth = 0;
    }

    public MaxWidthLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaxWidthLinearLayout);
        mMaxWidth = a.getDimensionPixelSize(R.styleable.MaxWidthLinearLayout_maxWidth, Integer.MAX_VALUE);
        a.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
        if (mMaxWidth > 0 && mMaxWidth < measuredWidth) {
            int measureMode = MeasureSpec.getMode(widthMeasureSpec);
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxWidth, measureMode);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

Et voici un lien pour l'utilisation de XML attr:
http://kevindion.com/2011/01/custom-xml-attributes-for-Android-widgets/

Merci pour cette question et réponses. Votre réponse m'a beaucoup aidé et j'espère que cela aidera quelqu'un d'autre à l'avenir également.

29
Jonypoins

Maintenant Android.support.constraint.ConstraintLayout facilite les choses. Enveloppez simplement votre vue (de tout type) avec ConstraintLayout et définissez les attributs suivants sur la vue:

Android:layout_width="0dp"
app:layout_constraintWidth_default="spread"
app:layout_constraintWidth_max="640dp"

http://tools.Android.com/recent/constraintlayoutbeta5isnowavailable

7

Ajoutez une couche de présentation externe ou de groupe de vues à votre fichier de disposition actuel. La hauteur et la largeur de cette disposition seront la hauteur/largeur maximale. Maintenant, votre disposition intérieure peut être définie pour envelopper le contenu et est limitée par la disposition extérieure. Par exemple:

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="vertical">

    <!-- OuterLayout to set Max Height and Width  -- Add this ViewGroup to your layout  File  -->
    <LinearLayout
        Android:id="@+id/outerLayout"
        Android:layout_width="650dp"
        Android:layout_height="650dp"
        Android:orientation="vertical" >

        <LinearLayout
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:orientation="vertical" >
        </LinearLayout>
    </LinearLayout>
</LinearLayout>
3
AmeyaB