如何通过编程动态创建Android UI组件列表?例如,TextView、ImageView等。

24

我正在创建一个程序,在其中需要创建所有不同的Android组件列表,但不是手动找出并输入List。我想要通过编程找出是否可以实现将其添加到类似以下的字符串数组中?

Components[] = {"TextView", "ImageView", "RelativeLayout", "LinearLayout", "Random", "DecimalFormat ...

同样地,我希望能够以编程方式创建一个List,其中包含所有不同的数据类型,例如Int、String、ArrayList等,以便添加到像下面这样的字符串数组中。

DataTypes[] = {"Int", "String", "Object", "Double", "Char", "Boolean ...

到目前为止,我已经完成的工作如上所示。 我目前是通过键入来完成它们。

我该如何实现这个呢?谢谢

澄清

数据类型:我指的是声明用于保存数据的变量类型,例如Int、String、object、boolean、double、arrays、arraylists等。

组件:我指的是可以添加到 Android 的 xml 中的任何可视化组件,如 ImageView、TextView、LinearLayout、RelativeLayout 等。

是的,我知道这些组件的数量可能是无限的(由使用的API确定),因此我希望能够动态生成它们。

最好不要使用别人的库


你想制作一个 UI 组件列表,但不使用 ListView 吗? - Balvinder Singh
请只发布您目前能够完成的内容。 - DJphy
如上所述,到目前为止我已经能够完成的内容如上所示。我希望将它们添加到字符串数组中,就像上面一样。 - user4934415
2
你能定义一下什么是“组件”和什么是“数据类型”吗? - Henry
你可以通过反射来实现这个功能,但是你应该问问自己是否真的想要做你所要求的事情。 - ligi
显示剩余4条评论
4个回答

10

你不必使用任何第三方库,因为Java拥有反射(reflections)。此方法将为您完成所有操作,并轻松创建UI

for(String s : arrayWithNames){
    View view = createViewInstance(0, s);
    if(view instance of View){
        //handle if it is view
    }else{
        //this is viewgroup
    }
}

关于 createViewInstance()

private View createViewInstance(String name){
    View view = null;
    try{
        if(name.equalsIgnoreCase("View"){ // if it is view
            Class viewClass = Class.forName("android.view." + name);
            view = (View) viewClass.getConstructor(Context.class).newInstance(new Object[]{ctx});
        }else{ // if it is widget: ImageView, RelativeLayout etc
            Class viewClass = Class.forName("android.widget." + name);
            view = (View) viewClass.getConstructor(Context.class).newInstance(new Object[]{ctx});
        }
    } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException
            | InstantiationException | IllegalAccessException e) {
        e.printStackTrace();
    }
    return view;
}

就是这样。您已经拥有了处理任何类型的 View 的所有内容。 我已经测试过上面的代码并在项目中使用过。它完美运行。 与其他 Object 相同的情况。您无法使用反射创建 int,但可以创建 Integer,因此基本上是相同的。

其中一个问题是除了 ViewViewGroup 之外,还有更多类型。但这也取决于您要创建多少种类型的 Object... 在给定的示例中,假设我将执行 charStringintObject,然后您可以轻松扩展它。

for(String s : arrayWithNames){
    if(s.equalsIgnoreCase("int")){
        Integer integer = (Integer)createVarInstance(s); //ready to use. Integer, not int!
    }else if(s.equalsIgnoreCase("String"){
        String string = (String)createVarInstance(s);
    }else if(s.equalsIgnoreCase("char"){
        Character character = (Character)createVarInstance(s); //Character, not char!
    }else if(s.equalsIgnoreCase("Object"){
        Object object = (Object)createVarInstance(s);
    }
}

由于所有这些数据类型都在同一个包中,这使得我们的工作更加容易。方法 createVarInstance():

private Object createVarInstance(String name){
    Object obj = null;
    try{
        Class varClass = Class.forName("java.lang." + name);
        object = (Object) varClass.newInstance();
    } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException
            | InstantiationException | IllegalAccessException e) {
        e.printStackTrace();
    }
    return object;
}
如果需要的话,可以为不同的包制作一个通用的方法。 如果将来您想创建更多不同类型的变量,这些变量位于不同的包中,那么您将不得不检查名称或执行与View类似的操作。

1
你可以使用反射库将UI组件中的所有类列出到android.view包或android.view.View子类中:
Reflections reflections = new Reflections("android.view");
//Reflections reflections = new Reflections("android.view.View");

Set<Class<? extends Object>> allClasses = reflections.getSubTypesOf(Object.class);

要创建所有数据类型的列表,您可以使用Object类执行与上面相同的操作,但首先,我个人会问自己这样做有什么意义。

1

Reflections 是 Java 中一个非常棒的库。我不确定它是否也可以在 Android 上使用。有人 提出了一个问题,但很快就被关闭了,没有解释。

如果你能让它在 Android 上正常工作,你可以使用这段代码来获取所有组件:

Reflections reflections = new Reflection("android.widget") //specifiy the package (TextView etc. are in here)
Set<Class<? extends View>> components = reflections.getSubTypesOf(View.class);

如果您愿意,可以按照同样的步骤处理android.view包,其中包含一些其他类,例如ViewGroup
此外,如果您真的需要一个字符串数组,请获取类的名称:
List<String> componentNames = new ArrayList<String>();
for (Class<? extends View> c: components) {
    componentNames.add(c.getName());
}
String[] allComponents = componentNames.toArray();

如果上述解决方案对您无效,请尝试从官方网站获取类。这些类列在android.viewandroid.widget包中。只需复制相关名称并将其粘贴到源代码中。这不会是动态的,但它有效。

0

你觉得使用工厂模式来创建组件怎么样?

public class ComponentFactory {
    private HashMap<String, View> mMap;
    public ComponentFactory(Context context) {
        mMap = new HashMap<String, View>();
        mMap.put("TextView", new TextView(context));
        ...
        ...
    }

    public View getComponent(String name) {
        View v = mMap.get(name);
        if (v == null) {
            throw new IlllegalArgumentException();
        }
        return v;
    }
}

我们如何为创建的元素提供操作,例如如果我想从编辑文本中获取文本或从Spinner中获取选定的项?如果您有示例,请在此处分享。 - Surya Reddy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接