10

私はプログラムで(XMLファイルを使用せずに)Androidでカスタムサブビューを作成しようとしています(これは私がiOSで呼んでいるものです)。これは基本的にいくつかの基本的なビュー(ラベル、ボタン、テキストフィールドなど)を再利用可能なサブビューにまとめたものですクラスを作成して、自分の内部UIViewControllersまたはActivityAndroid で使用できるようにしました。

Android の正しい用語がわかりません。何百万もの異なる用語があるようです。

Custom View、ViewGroups、Layouts、Widgets、Components など、お好きな名前を付けてください。

iOS では、これは次のように単純に行われます。

CustomView.h

@interface CustomView : UIView

@property (nonatomic, strong) UILabel *message;
@property (nonatomic, strong) UIButton *button;

@end

CustomView.m

@implementation CustomView

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    if(self)
    {
        [self initViews];
        [self initConstraints];
    }

    return self;
}

-(void)initViews
{
    self.message = [[UILabel alloc] init];
    self.button = [[UIButton alloc] init];

    [self addSubview:self.message];
    [self addSubview:self.button];
}

-(void)initConstraints
{
    id views = @{
                 @"message": self.message,
                 @"button": self.button
                 };

    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[message]|" options:0 metrics:nil views:views]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[button]|" options:0 metrics:nil views:views]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[message][button]|" options:0 metrics:nil views:views]];
}

@end

これで、選択した任意の ViewController (Android Activity) でこのカスタム ビューを再利用できます。

Androidでそのようなことをどのように達成しますか?

私は周りを見回しており、Androidで収集したものから、サブビューを追加するために、それらを次の場所に追加しますLayouts:

RelativeLayout relativeLayout = new RelativeLayout(...);
TextView textView = new TextView(...);

relativeLayout.addSubview(textView);

それは私が拡張する必要があるということですRelativeLayoutViewGroup

このページを見る: http://developer.android.com/reference/android/view/ViewGroup.html

カスタム ビューをレイアウトするには、次のような非常に複雑なロジックを記述する必要があるようです。

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int count = getChildCount();

        // These keep track of the space we are using on the left and right for
        // views positioned there; we need member variables so we can also use
        // these for layout later.
        mLeftWidth = 0;
        mRightWidth = 0;

        // Measurement will ultimately be computing these values.
        int maxHeight = 0;
        int maxWidth = 0;
        int childState = 0;

        // Iterate through all children, measuring them and computing our dimensions
        // from their size.
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                // Measure the child.
                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);

                // Update our size information based on the layout params.  Children
                // that asked to be positioned on the left or right go in those gutters.
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                if (lp.position == LayoutParams.POSITION_LEFT) {
                    mLeftWidth += Math.max(maxWidth,
                            child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
                } else if (lp.position == LayoutParams.POSITION_RIGHT) {
                    mRightWidth += Math.max(maxWidth,
                            child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
                } else {
                    maxWidth = Math.max(maxWidth,
                            child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
                }
                maxHeight = Math.max(maxHeight,
                        child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
                childState = combineMeasuredStates(childState, child.getMeasuredState());
            }
        }

        // Total width is the maximum width of all inner children plus the gutters.
        maxWidth += mLeftWidth + mRightWidth;

        // Check against our minimum height and width
        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());

        // Report our final dimensions.
        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                resolveSizeAndState(maxHeight, heightMeasureSpec,
                        childState << MEASURED_HEIGHT_STATE_SHIFT));
    }

私がやろうとしているのは、上記の iOS の例のようなカスタム ビューで複数の基本的な Android ラベル、ビュー、ボタンを使用することだけですが、Android ではなぜ難しいのでしょうか?

私はこのような単純なものを望んでいました:

public class CustomView extends View
{
    public RelativeLayout mainLayout;

    public TextView message;
    public Button button;

    // default constructor
    public CustomView()
    {
        ...

        initViews();
        initLayouts();
        addViews();
    }

    public initViews()
    {
        mainLayout = new RelativeLayout(this);

        message = new TextView(this);

        button = new Button(this);

        ...
    }

    public initLayouts()
    {
        // --------------------------------------------------
        // use Android layout params to position subviews 
        // within this custom view class
        // --------------------------------------------------
    }

    public addViews()
    {
        mainLayout.addView(message);
        mainLayout.addView(button);

        setContentView(mainLayout);  
    }
}

申し訳ありませんが、基本的な Android アプリケーションの学習と構築に真摯に取り組んでおり、Android のやり方を否定するつもりはありません。

アクティビティ内にサブビューを追加してレイアウトする方法を知っており、過去 2 日間そうしていますが、カスタム ビュー/ビュー グループ/レイアウト内ではそうしていません。Android アプリのアクティビティごとにまったく同じサブビューを作成することはしたくありません。これは、適切なコーディング プラクティスに反するだけです。:D

ここでは、iOS と Android の両方の開発を行った他の人からのちょっとしたガイダンスが必要です。

編集

私が探しているのは複合コントロールと呼ばれているようです: http://developer.android.com/guide/topics/ui/custom-components.html

私は掘り続けて、うまくいけば私が求めている結果を達成します:D

このインフレータ事業を解決する必要があります。

4

3 に答える 3

1

OK、それが最善の解決策かどうかはわかりませんが、私が望むことはできます。

したがって、次のようになります。

public class CustomView extends RelativeLayout
{
    private Context context;

    public TextView message;
    public Button button;

    public CustomView(Context context)
    {
        super(context);

        // ---------------------------------------------------------
        // store context as I like to create the views inside 
        // initViews() method rather than in the constructor
        // ---------------------------------------------------------
        this.context = context;

        initViews();
        initLayouts();
        addViews();
    }

    public CustomView(Context context, AttributeSet attrs)
    {
        super(context, attrs);

        // ---------------------------------------------------------
        // store context as I like to create the views inside 
        // initViews() method rather than in the constructor
        // ---------------------------------------------------------
        this.context = context;

        initViews();
        initLayouts();
        addViews();
    }

    public initViews()
    {
        // ----------------------------------------
        // note "context" refers to this.context
        // that we stored above.
        // ----------------------------------------
        message = new TextView(context);
        ...

        button = new Button(context);
        ...

    }

    public initLayouts()
    {
        // --------------------------------------------------
        // use Android layout params to position subviews 
        // within this custom view class
        // --------------------------------------------------

        message.setId(View.generateViewId());
        button.setId(View.generateViewId());

        RelativeLayout.LayoutParams messageLayoutParams = new RelativeLayout.LayoutParams(
                LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT
        );

        message.setLayoutParams(messageLayoutParams);


        RelativeLayout.LayoutParams buttonLayoutParams = new RelativeLayout.LayoutParams(
                LayoutParams.MATCH_PARENT,
                LayoutParams.WRAP_CONTENT
        );

        button.setLayoutParams(buttonLayoutParams);
    }

    public addViews()
    {
        // adding subviews to layout
        addView(message);
        addView(button); 
    }
}

これで、任意のアクティビティでこのカスタム ビューを使用できます。

public class MainActivity extends ActionBarActivity {

    // custom view instance
    protected CustomView approvalView;

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ...
            initViews();
        }

        public initViews()
        {
            ...

            approvalView = new CustomView(this);
            approvalView.message.setText("1 + 1 = 2");
            approvalView.button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Log.d("Logger", "Math formula approved! :D");
                }
            });

        }
}

XML を使用してレイアウトを作成する場合はインフレータが使用されますが、これは私がやりたくないことなので、プログラムでビューのレイアウトを生成しました:D

上記の「extends RelativeLayout」の「RelativeLayout」は、もちろん「LinearLayout」や他のレイアウトに置き換えることができます。

于 2015-05-10T14:05:01.523 に答える