Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/217.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
创建类似iOS子视图的Android子视图_Android_Ios_Android Custom View_Android Viewgroup - Fatal编程技术网

创建类似iOS子视图的Android子视图

创建类似iOS子视图的Android子视图,android,ios,android-custom-view,android-viewgroup,Android,Ios,Android Custom View,Android Viewgroup,我试图以编程方式创建Android中的自定义子视图(我在iOS中称之为自定义子视图),这基本上是一系列基本视图(标签、按钮、文本字段等)放在一个可重用的子视图类中,这样我就可以在Android中的UIViewControllers或Activity中使用它 我不知道Android的正确术语是什么。似乎有一百万种不同的术语 自定义视图、视图组、布局、小部件、组件,无论您如何称呼它 在iOS中,这样做很简单: public class CustomView extends View { pu

我试图以编程方式创建Android中的自定义子视图(我在iOS中称之为自定义子视图),这基本上是一系列基本视图(标签、按钮、文本字段等)放在一个可重用的子视图类中,这样我就可以在Android中的
UIViewControllers
Activity
中使用它

我不知道Android的正确术语是什么。似乎有一百万种不同的术语

自定义视图、视图组、布局、小部件、组件,无论您如何称呼它

在iOS中,这样做很简单:

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);  
    }
}
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); 
    }
}
CustomView.h CustomView.m 现在我可以在我选择的任何ViewController(Android
Activity
)中重用此自定义视图

在安卓系统中,人们是如何做到这一点的

我一直在环顾四周,从我在Android中收集的信息中,为了添加子视图,我将它们添加到
布局中

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

relativeLayout.addSubview(textView);
这是否意味着我需要扩展
RelativeLayout
ViewGroup

请看本页:

似乎我们需要编写一些非常复杂的逻辑来布局自定义视图,例如:

@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));
    }
很抱歉,我真诚地尝试学习和构建一个基本的Android应用程序,而不是试图抨击Android的做事方式

我知道如何在活动中添加和布局子视图,在过去的两天里我一直在这样做,但在自定义视图/视图组/布局中却没有。我不想在Android应用程序中为我的每个活动构建完全相同的子视图,这与良好的编码实践背道而驰,对吧D

在这里,我们只需要从其他同时开发过iOS和Android的人那里得到一些指导

编辑 看起来我要找的是一个复合控件:

我会继续努力,希望能达到我想要的结果:D


只需要解决这个充气机业务。

Android和ios应用程序开发是两个不同的概念,每个都有自己的方式来执行任务。有时在android中开发一段代码很困难,有时在ios中也很困难。 要在android中创建视图屏幕/设计/GUI,您可以创建XML文件(推荐)或代码(维护w.r.t XML有点困难)

对于您的问题,您不需要创建自己的
ViewGroup
RelativeLayout
LinearLayout
例如,如果您想使用
RelativeLayout
作为视图的父视图,而不是使用XML,您可以使用

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Some Text"/>
</RelativeLayout>
这只是一个示例代码,两个代码都有相同的输出,但随着视图的增长,使用编程方法将很困难

查看您的代码您正在创建自定义视图(为什么?)在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);  
    }
}
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


“扩展相对布局”中的上述“相对布局”当然可以替换为“线性布局”或其他布局。

要为普通访问者添加此问题的简单答案

您不能像使用iOS
UIView
那样,向Android
视图添加子视图

如果您需要在Android中添加子视图,那么可以使用
ViewGroup
子类之一(比如
LinearLayout
RelativeLayout
,甚至您自己的自定义子类)


为什么不呢?在开发应用程序时,有时需要在界面中使用可重用组件,例如自定义弹出警报确认对话框,其中可能包括标题标签、问题标签、文本字段和确认按钮。你不想重复你的代码,在每一个单独的活动中构造相同的弹出视图。您可以编写一个可重用的自定义视图,将其导入活动并创建其实例。这不是重新发明轮子,而是使用基本组件构建更复杂的可重用视图。我理解你的观点,我推荐你这样做。我的意思是,如果并且仅当您需要默认情况下不可用的更多/额外内容时,您应该使用自定义视图。是的,如果你想在整个应用程序中使用相同的弹出窗口,那么你可以在代码中创建弹出窗口警报,并在任何时间、任何地点调用函数/方法。Android提供了一个弹出对话框,如果你要去创建自定义对话框扩展对话框,它与默认对话框相同,而不是再次发明轮子,但是如果你要使用默认对话框,使用它的属性进行化妆和使用,这是可重用的。我不认为你会这样做。我想我在Android中称之为复合控件:。基本的Android对话框视图(带有取消和确认按钮的标签)是谷歌为我们编写的复合视图。它将文本视图和按钮视图合并成一个新的可重用类,称为“Dialog”。这个概念类似于扩展基类的面向对象编程。子类继承自基类,并添加了自己的属性和函数,它不是在重新发明轮子。例如,如果我得到一个“Square”类,它就有一个宽度和高度。如果我从该类继承并添加一个新属性“length”来形成一个名为“Cube”的新类,这是不是在重新发明轮子?同样,我从Android View类继承并添加新的“属性”,例如TextView、Yes按钮和No按钮,并将该类称为“TrueOrFalseView”。这不是重新发明轮子,而是扩展视图类
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");
                }
            });

        }
}
myViewGroup.addView(myView);