如何在Android布局中动态绘制一条线

3

我已经完成的工作:

图1

我正在寻找的内容:

图2

我不关心设计,但我不知道如何使用类似于第二张图片的线将按钮连接到主按钮。 注意:我是动态创建按钮的。因此,我不使用XML文件,因为我不知道会有多少行/按钮。

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.second_layout);
    //
    RelativeLayout FirstLayout = (RelativeLayout)findViewById(R.id.second_layou);
    RelativeLayout.LayoutParams parms1 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    Button yourButton = new Button(this);
    yourButton.setText("1");
    yourButton.setWidth(2);
    parms1.setMargins(w, h+250, 0, 0);
    FirstLayout.addView(yourButton, parms1);
    //
    RelativeLayout.LayoutParams parms2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    Button yourButton2 = new Button(this);
    yourButton2.setText("2");
    yourButton2.setWidth(2);
    parms2.setMargins(w-300, h+300, 0, 0);
    FirstLayout.addView(yourButton2, parms2);
    // and so on with other buttons

编辑:

首先: 我尝试了这个答案,将以下代码添加到onCreate()的末尾:

drawView = new DrawView(this);
        drawView.setBackgroundColor(Color.WHITE);
        setContentView(drawView);

一条线视图被显示出来了,但是按钮却消失了!我想让这条线从MAIN按钮的中心点到其他按钮的中心点绘制,而不是从固定点开始。

第二个问题:当我在定义按钮之前添加相同的代码时,会出现运行时错误,以下是日志记录:

01-29 15:25:25.956 26170-26170/com.example.user.raywenderlich E/AndroidRuntime: FATAL EXCEPTION: main                                                                         Process: com.example.user.raywenderlich, PID: 26170                                                                              java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.user.raywenderlich/com.example.user.raywenderlich.SecondActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.RelativeLayout.addView(android.view.View, android.view.ViewGroup$LayoutParams)' on a null object reference
                                                                                    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2411)
                                                                                    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474)
                                                                                    at android.app.ActivityThread.access$800(ActivityThread.java:144)
                                                                                    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359)
                                                                                    at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                    at android.os.Looper.loop(Looper.java:155)
                                                                                    at android.app.ActivityThread.main(ActivityThread.java:5696)
                                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                                    at java.lang.reflect.Method.invoke(Method.java:372)
                                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
                                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
                                                                                 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.RelativeLayout.addView(android.view.View, android.view.ViewGroup$LayoutParams)' on a null object reference
                                                                                    at com.example.user.raywenderlich.SecondActivity.onCreate(SecondActivity.java:46)
                                                                                    at android.app.Activity.performCreate(Activity.java:5958)
                                                                                    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129)
                                                                                    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
                                                                                    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474) 
                                                                                    at android.app.ActivityThread.access$800(ActivityThread.java:144) 
                                                                                    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359) 
                                                                                    at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                    at android.os.Looper.loop(Looper.java:155) 
                                                                                    at android.app.ActivityThread.main(ActivityThread.java:5696) 
                                                                                    at java.lang.reflect.Method.invoke(Native Method) 
                                                                                    at java.lang.reflect.Method.invoke(Method.java:372) 
                                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028) 
                                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)

 


你可以使用Python的subprocess模块来运行外部命令。下面是一个简单的例子:import subprocess # 运行ls命令并将结果存储在result变量中 result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE) # 打印结果 print(result.stdout.decode('utf-8'))在这个例子中,我们使用subprocess.run()函数来运行ls -l命令,并将结果存储在result变量中。然后,我们使用print()函数打印结果。请注意,subprocess.run()函数返回一个CompletedProcess对象,该对象包含有关进程的信息,例如退出代码和输出。在上面的例子中,我们使用stdout=subprocess.PIPE参数将输出重定向到管道,以便我们可以在程序中访问它。最后,我们使用decode('utf-8')方法将字节字符串转换为Unicode字符串,以便我们可以正确地打印它。 - Gueorgui Obregon
出现了运行时错误,请提供您的日志记录。 - OneCricketeer
1
findViewById(R.id.second_layou) 返回 null,因为它在您为 Activity 定义的内容视图中找不到该 ID。可能是因为您已经执行了 setContentView(drawView);,这意味着 findViewById 将不再起作用。 - OneCricketeer
1
我认为这也是一个打字错误,因为你在它上面有 setContentView(R.layout.second_layout); - OneCricketeer
1
只需将新视图直接添加到当前视图上,不要完全替换它。 - OneCricketeer
显示剩余4条评论
1个回答

2
“我实际上需要类似的东西,但很失望没有答案。”
“经过一些搜索和信息的组合,我得到了这个状态:”

Some textviews connected by curved lines.


我所做的是使用一个FrameLayout,这样TextView可以堆叠在绘图View的上方。我按照基本绘画教程中建议的制作了一个自定义的绘画View。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root_layout">

   <com.dev.example.CustomDrawingView
       android:id="@+id/custom_drawing_view"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>

</FrameLayout>

然后我通过代码动态地将TextView添加到FrameLayout中,并使用Path对象在CustomDrawingView中绘制线条,从每个TextView的中心到中心:
Path path = new Path();

int x1 = (int) firstView.getX() + firstView.getWidth() / 2;
int y1 = (int) firstView.getY() + firstView.getHeight() / 2;

int x2 = (int) secondView.getX() + secondView.getWidth() / 2;
int y2 = (int) secondView.getY() + secondView.getHeight() / 2;

path.moveTo(x1, y1);
path.lineTo(x2, y2);

现在,这条曲线是根据这个问题的答案制作的:如何在画布上绘制两点之间的曲线? 只需调整那个答案中的curveRadius即可获得不同外观的曲线。
希望这能帮助未来的某个人。
编辑:还有非常重要的一点是,在所有布局和视图都被显示后才调用CustomDrawingView的onDraw方法。否则,TextView的getX()和getY()方法仍然返回0,你将看不到任何线条。建议在活动的onWindowFocusChanged方法中开始绘制它们。

@Jaichander 抱歉没有在Github上。 - Big_Chair

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