【问题标题】:Dynamically add multiple views and classes to the current view将多个视图和类动态添加到当前视图
【发布时间】:2013-05-14 04:07:14
【问题描述】:

我有兴趣使用用户定义的相同视图数量填充屏幕/活动。每个视图都将具有完全相同的布局:几个 TextView 和几个 Button。问题是每个按钮都将控制每个 TextView 将显示的内容。

我想实现它的方式是拥有一个 XML 和一个 Java 类。然后根据用户输入的数字,用相同的视图填充屏幕(使用 for 循环)。问题是,能做到吗?如何?我是否以正确的方式考虑它?

如有任何意见或想法,请提供帮助,代码示例也会很棒。

【问题讨论】:

  • 我什么都没试过。我一直在阅读最好和最有效的方法。我见过 Fragments、inflators 和 listview。但我希望让它对每个单独添加的视图上的按钮按下作出反应。我找不到对此的书面解释。
  • 你应该删除你的问题。你会像地狱一样被标记和投票。
  • 那是我一直在寻找的另一件事。如何删除问题?
  • 标签下方有删除按钮

标签: android dynamic view


【解决方案1】:

当然可以。

我认为最适合您的情况,而且您可以轻松扩展,是创建一些帮助函数来处理:

1) 创建一个空屏幕 2)为屏幕创建一个按钮 3)为屏幕创建一个文本视图 最后 4) 创建一个屏幕并填充它

你必须为你的视图决定合适的根元素,这取决于你需要的子元素。为简单起见,我们选择 LinearLayout,但对于 RelativeLayout 或 TableLayout,示例是相同的,只是在添加元素时,必须使用附加参数才能正确放置它们。

请注意,创建一个空的自定义视图的函数返回一个 ViewGroup(“所有布局的来源”)。这样,您始终使用 ViewGroups,并且只需在 createCustomView 中定义一次屏幕布局类型。所以你可以在那里改变屏幕的类型,剩下的代码就可以工作了……

这里有一些代码可以激发你的灵感:

private ViewGroup createCustomView(Context context) {

    LinearLayout myCoolNewView=new LinearLayout(context); // or RelativeLayout, etc..
    return myCoolNewView;
} 

private Button createButton(Context context, String buttonText) {
    Button newButton=new Button(context);
    newButton.setText(buttonText);
    return newButton;
}

private TextView createText(Context context, String initialText) {
    TextView newText=new TextView(context);
    newText.setText(buttonText);
    return newText;
}

private ViewGroup createScreen(Context context, int numberOfButtons, int numberOfTextfields) {

    ViewGroup newScreen=createCustomView(context);
    TextView[] textViews=new TextView[numberOfTextFields];

    for (int i=0; i<numberOfTextfields; i++) {
          textViews[i]=createText(context, "hi i am text "+i);
           newScreen.addView(textViews[i]); // you ideally provide here layoutparams to properly place your buttons

    }
    for (int j=0; i<numberOfButtons; j++) {
          Button button=createButton(context, "hi i am button "+j);
          button.setOnClickListener(new OnClickListener() {
              public void onClick (View clickedView) {
                    // here you have a button keypress and you know all the textviews
                    textView[i%j].setText("hey you pressed me");
              }
          });
          newScreen.addView(button);
    }
    return newScreen;
}

所以现在你可以:

ViewGroup screen1=createScreen(context, 10, 10);
ViewGroup screen2=createScreen(context, 5, 3);
ViewGroup screen3=createScreen(context, 2, 5);

并将屏幕添加到父布局、ViewFlipper、ViewSwitcher 等......就像这样:

 ViewGroup parentLayoutOfAllScreens=findViewById(R.id.root_of_screens);
 parentLayoutOfAllScreens.addView(screen1);
 parentLayoutOfAllScreens.addView(screen2);
 parentLayoutOfAllScreens.addView(screen3);

在 XML 中,您只需创建根布局,并将其命名为 root_of_screens...

编码好!!!我想上面的代码会有一些错误,只是在这里输入,但我希望你能明白并调整它以满足你的需要!

编辑:v2.0:扩展视图 在您的活动所在的同一文件夹中创建一个名为“MyCoolScreen.java”或任何名称的新 .java(为简单起见):

package ........
public class MyCoolScreen extends LinearLayout {

    /** Now every view holds its own buttons, and they are private, it's good for encapsulating */
    private TextView[] mTextViews; // <-- as a convention, members should start with "m"
    private Button[] mButtons;
    private UserPressedButtons mUserPressedButtonsListener; // See below

    /** The following constructors must always be present for a custom view, and must always call super */
    public MyCoolScreen(Context context) {
        // This is the constructor you will use when creating your view programmatically
        super(context);
    }

    public MyCoolScreen(Context context, AttributeSet attrs) {

        // This is the constructor Android calls when you include your custom view in an XML
        // You can do this too!! 
        // The ATTRS will then include your numberofbuttons and numberoftextfields from the XML
        // this is beyond the example, but read about it, it's interesting

        super(context, attrs); // this MUST ALWAYS be here for custom views, or they will not work.
                               // it tells the parent view to continue the construction.
    }

    public MyCoolScreen(Context context, AttributeSet attrs, int defStyle) {
        // Another constructor Android calls from the XML
        super(context, attrs, defStyle); 
    }


    /** We create an "init" method to initialize this view from outside */
    public void init(int numberOfTextViews, int numberOfButtons) {
        createScreen(numberOfTextViews, numberOfButtons);
    }


    /** This is the same */
    private Button createButton(Context context, String buttonText) {
        Button newButton=new Button(context);
        newButton.setText(buttonText);
        return newButton;
    }

    /** This is the same */
    private TextView createText(Context context, String initialText) {
        TextView newText=new TextView(context);
        newText.setText(buttonText);
        return newText;
    }

    /** We tweak this function so it doesnt return a view, but rather fills up this one :) */

    private void createScreen(int numberOfButtons, int numberOfTextfields) {

        ViewGroup newScreen=this; // It's this view the one we gonna fill up!
        mTextViews=new TextView[numberOfTextfields];
        mButtons=new Button[numberOfButtons];
        Context context=getContext(); // Views always know their context after constructed

        for (int i=0; i<numberOfTextfields; i++) {
              mTextViews[i]=createText(context, "hi i am text "+i);
              newScreen.addView(textViews[i]); // you ideally provide here layoutparams to properly place your buttons
        }

        for (int j=0; i<numberOfButtons; j++) {
              Button button=createButton(context, "hi i am button "+j);
              button.setId(j);
              button.setOnClickListener(new OnClickListener() {
                  public void onClick (View clickedView) {
                        // here you have a button keypress and you know all the textviews
                        if (mUserPressedButtonsListener!=null) mUserPressedButtonsListener.OnButtonPressed(j);
                        textView[i%j].setText("hey you pressed me");
                  }
              });
              mButtons[j]=button;
              newScreen.addView(button);
        }
    }

    public interface UserPressedButtons {
        public void OnButtonPressed(int buttonNumber);
    }

    public void setUserPressedButtonsListener (UserPressedButtons listener) {
         mUserPressedButtonsListener=listener;
    }
}

好的,现在要在您的 Activity 中使用它:

    import ....... .MyCoolScreen;
    import ....... .MyCoolScreen.UserPressedButtons;

    .
    .
    .

    MyCoolScreen screen1=new MyCoolScreen(context);
    screen1.init(5,5); // initializes the screen.

    myRootLayout.addView(screen1);

这很酷,现在功能完全封装在您的自定义视图中。而且它驻留在另一个 .java 中,因此您的活动代码非常干净,您甚至可以扩展 View 功能而不会使其变得丑陋。

为您的视图创建接口和侦听器以与外界通信也是一种常见的做法,例如,我们可以这样做:

     screen1.setUserPressedButtonsListener(new MyCoolScreen.UserPressedButtons() {
         @Override
         public void OnButtonPressed (int number) {
              // you know the user pressed button "number", and you can do stuff about it without
              // having to include it inside the MyCoolScreen class. Of course in your example you
              // don't need this at the moment, because the View will modify its textfield, but suppose
              // one of the buttons is "rocket launch" , that is something you will handle at the activity level, ie.

              if (number==ROCKET_LAUNCH) RocketLauncher.setTarget(10,10).launch(); // Your MyCoolScreen doesnt know how to launch rockets, but your activity maybe yes...

         }
     });

您可以使用新的自定义视图做各种很酷的事情。例如,您可以定义:

     @Override
     public void OnDraw(Canvas c) {
          c.drawEllipse ...
          c.drawRectangle ....
     }

您可以在文本字段和按钮上绘制圆圈、线条等...

    setWillNotDraw(false) on the constructor.

可能有错误,这里只是打了代码,希望对你有帮助!

【讨论】:

  • 我没有测试过这段代码,但看起来是对的。就像我想做的那样。我缺少的东西,你的帖子提出了解决方案的想法,是为每个创建的元素生成唯一的 ID。我会为每个添加的元素添加到您的代码.setId(i);。 :-) 太晚了,明天我会测试它并回复。 -干杯
  • noprob :) 但是现在你知道了 setId,让我告诉你有关 setTag() 的信息。这是老表弟,这样您就可以将任何内容分配给按钮,而不仅仅是 id。您可以这样做:view.setTag("my button") 或 view.setTag(new String[]{"button1","screen2"}) 甚至 view.setTag(new MyStuffInfo(a,b,c,d ,e))) .... 然后执行 view.getTag() 来获取它:)
  • 它就像一个魅力(在大量修改你的代码以适应我想要的前景之后)。现在,我遇到了 LinearLayout 中的 id 和 tag 以及元素顺序的问题。无法确定在 onClick 按钮中回调 TextViews 的正确方法。
  • 对于该问题,您可以将所有文本字段保留在屏幕级别的数组中,例如,然后指定为按钮 ID 或标记文本字段的数组索引。在 OnClick 中,您将单击的视图作为参数,因此按钮 id 将是文本字段索引。顺便说一句,“专业”的方式是创建一个扩展 LinearLayout 的 Screen 类,其中包含填充它的逻辑,并引用它自己的文本字段和按钮。这样每个屏幕将彼此分离,您面临的问题将更容易解决。如果您需要有关此的代码示例,请告诉我...
  • 如果我理解您的“专业”方式 - 那么它就是我最初想要的方式 - 但不知道如何。因为 MainScreen 托管所有视图 - 它们是相同的 - 我想重复相同的视图,就像用户定义的一样多次。那就是我碰壁的地方,您的解决方案就派上用场了。如果可以的话,一个代码示例会很棒。
【解决方案2】:

【讨论】:

  • 我之前已经通读过了。它不是我要找的。我希望动态添加几个视图——它们源自一个视图——并且能够独立控制每个视图的事件。为每个单独的视图更改 TextViews 和 ImageViews 等事件。
猜你喜欢
  • 1970-01-01
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多