gpt4 book ai didi

android - 两个 View 之间的自定义画线无法正常工作

转载 作者:行者123 更新时间:2023-12-05 07:39:41 26 4
gpt4 key购买 nike

我正在尝试在 android 中的按钮之间画线。我创建了一个自定义类,它在相对布局内的按钮之间画线(相对布局是父布局)。

Here is my MatchTheColoumnDrawView.java class which accepts context, startView, endView, lineColour, endCircleColour, thickness(in float), direction(LEFT_TO_RIGHT OR RIGHT_TO_LEFT).

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.Log;
import android.view.View;

/**
* Created by Abhishek on 12/21/2016.
*
* Changes made as per new design on Date 9 Oct 2017
*
*/

public class MatchTheColumnDrawView extends View {


public static final int LEFT_TO_RIGHT = 1, RIGHT_TO_LEFT = 2;

private Paint mLinePaint, mCirclePaint;

private View startView, endView;

private int direction;

private Canvas canvas;

private float dashWidth = 15f;

private float dashGap = 8f;

float[] intervals = new float[]{dashWidth, dashGap};

float phase = 0;

private int LINE_COLOR = Color.parseColor("#BEBEBE");

private int END_CIRCLE_COLOR = Color.parseColor("#FF99CC00");

/**
*
* parametrised constructor draws line from
* @startView
* to
* @endView
* as per
* @direction
* and
* @lineColor
* and
* @endCircleColor
*
* when
* @lineColor == null
* default lineColor is gray
*
* when
* @endCircleColor == null
* default endCircleColor is green
* */

public MatchTheColumnDrawView(Context context,
View startView, View endView,
String lineColor, String endCircleColor,
float thickness, int direction) {

super(context);

mLinePaint = new Paint();
if (lineColor != null) LINE_COLOR = Color.parseColor(lineColor);
mLinePaint.setColor(LINE_COLOR);
mLinePaint.setStrokeWidth(thickness);
mLinePaint.setStyle(Paint.Style.STROKE);

mCirclePaint = new Paint();
if (endCircleColor != null) END_CIRCLE_COLOR = Color.parseColor(endCircleColor);
mCirclePaint.setColor(END_CIRCLE_COLOR);
mCirclePaint.setStrokeWidth(thickness);

this.startView = startView;
this.endView = endView;
this.direction = direction;

//setBackgroundColor To Transparent
super.setBackgroundColor(Color.TRANSPARENT);
}

public View getStartView() {
return startView;
}

public void setStartView(View startView) {
this.startView = startView;
}

public View getEndView() {
return endView;
}

public void setEndView(View endView) {
this.endView = endView;
}

public Canvas getCanvas() {
return canvas;
}

public int getDirection() {
return direction;
}

public void setDirection(int direction) {
this.direction = direction;
}

@Override
protected void onDraw(Canvas canvas) {

this.canvas = canvas;

Log.d("Direction", String.valueOf(direction));

Log.d("Start View Y:", String.valueOf(startView.getY()));
Log.d("Start View H:", String.valueOf(startView.getHeight()));

Log.d("End View Y:", String.valueOf(endView.getY()));
Log.d("End View H:", String.valueOf(endView.getHeight()));

//By default takes LEFT_TO_RIGHT

if (direction == RIGHT_TO_LEFT) {

//For RIGHT TO LEFT
//Calculating Left X And Mid Of Height Y
/*
* ______________
* | |
* This Point ==>> .| |
* | |
* |______________|
* */

float startViewLeftX = startView.getX();
float startViewMidHeightY = startView.getY() + startView.getHeight() / 2;

//Calculating Right X And Mid Of Height Y
/*
* ______________
* | |
* | |. <<== This Point
* | |
* |______________|
* */

float endViewRightX = endView.getX() + endView.getWidth(); //20 is just to remove unwanted padding on Right Side
float endViewMidHeightY = endView.getY() + endView.getHeight() / 2;

Path mPath = new Path();

mPath.moveTo(startViewLeftX, startViewMidHeightY);
mPath.lineTo(endViewRightX, endViewMidHeightY);

DashPathEffect dashPathEffect = new DashPathEffect(intervals, phase);

mLinePaint.setPathEffect(dashPathEffect);

canvas.drawPath(mPath, mLinePaint);

//canvas.drawLine(startViewLeftX, startViewMidHeightY, endViewRightX, endViewMidHeightY, mLinePaint);
canvas.drawCircle(startViewLeftX, startViewMidHeightY, 5, mCirclePaint);
canvas.drawCircle(endViewRightX, endViewMidHeightY, 5, mCirclePaint);
} else {

//FOR LEFT_TO_RIGHT
//Calculating Right X And Mid Of Height Y
/*
* ______________
* | |
* | |. <<== This Point
* | |
* |______________|
* */

float startViewRightX = startView.getX() + startView.getWidth(); //20 is just to remove unwanted padding on Right Side
float startViewMidHeightY = startView.getY() + startView.getHeight() / 2;

//Calculating Left X And Mid Of Height Y
/*
* ______________
* | |
* This Point ==>> .| |
* | |
* |______________|
* */

float endViewLeftX = endView.getX();
float endViewMidHeightY = endView.getY() + endView.getHeight() / 2;

Path mPath = new Path();

mPath.moveTo(startViewRightX, startViewMidHeightY);
mPath.lineTo(endViewLeftX, endViewMidHeightY);

DashPathEffect dashPathEffect = new DashPathEffect(intervals, phase);

mLinePaint.setPathEffect(dashPathEffect);

canvas.drawPath(mPath, mLinePaint);
//canvas.drawLine(startViewRightX, startViewMidHeightY, endViewLeftX, endViewMidHeightY, mLinePaint);
canvas.drawCircle(startViewRightX, startViewMidHeightY, 5, mCirclePaint);
canvas.drawCircle(endViewLeftX, endViewMidHeightY, 5, mCirclePaint);
}
}

@Override
public void setBackgroundColor(int color) {
super.setBackgroundColor(color);
}


}

I wrote one class MatchTheFollowingAttempted which extend Relative layout and it contains logic for drawing buttons and lines between them. Here is MatchTheFollowingAttempted.java class.

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.RelativeLayout;

import java.util.ArrayList;

/**
* Created by Abhishek on 24-10-2017.
*/

public class MatchTheFollowingAttempted extends RelativeLayout {

private Context mContext;

int numberOfOneSideButtons = 5;


public MatchTheFollowingAttempted(Context context) {
super(context);
mContext = context;
initialiseView();
}

public MatchTheFollowingAttempted(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
initialiseView();
}

public MatchTheFollowingAttempted(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
initialiseView();
}

public MatchTheFollowingAttempted(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mContext = context;
initialiseView();
}

public void initialiseView() {

ArrayList<Button> leftSideButtons = new ArrayList<>();
ArrayList<Button> rightSideButtons = new ArrayList<>();
ArrayList<MatchTheColumnDrawView> matchTheColumnDrawViewArrayList = new ArrayList<>();


for (int i = 0; i < numberOfOneSideButtons; i++) {

Button mButton = new Button(mContext);

mButton.setId(View.generateViewId());

RelativeLayout.LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

if (i != 0) {

layoutParams.addRule(BELOW, leftSideButtons.get(i-1).getId());

}

layoutParams.setMargins(10, 10, 10, 10);

mButton.setLayoutParams(layoutParams);

leftSideButtons.add(mButton);

addView(mButton);


}

for (int i = 0; i < numberOfOneSideButtons; i++) {

Button mButton = new Button(mContext);

mButton.setId(View.generateViewId());

RelativeLayout.LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

layoutParams.addRule(ALIGN_PARENT_RIGHT);

if (i != 0) {

layoutParams.addRule(BELOW, rightSideButtons.get(i-1).getId());

}

layoutParams.setMargins(10, 10, 10, 10);

mButton.setLayoutParams(layoutParams);

rightSideButtons.add(mButton);

addView(mButton);

}

for (int i = 0; i < numberOfOneSideButtons; i++) {

MatchTheColumnDrawView matchTheColumnDrawView = new MatchTheColumnDrawView(mContext, leftSideButtons.get(i), rightSideButtons.get(4-i), null, null, 2.0f, MatchTheColumnDrawView.LEFT_TO_RIGHT);

matchTheColumnDrawViewArrayList.add(matchTheColumnDrawView);

addView(matchTheColumnDrawView);
}



}

}

When I directly use MatchTheFollowingAttempted inside LinearLayout(Inside Scrollview) it will shows view properly with buttons and lines between them. As shown in image attached(Image_One). Here is the xml for it.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<MatchTheFollowingAttempted
android:layout_width="match_parent"
android:layout_height="wrap_content">

</MatchTheFollowingAttempted>

</LinearLayout>

</ScrollView>

</RelativeLayout>

Image_One

But when I add second MatchTheFollowingAttempted in Linear Layout Then Lines will not shown(As in attached image Image_Two). Here is xml with two MatchTheFollowingAttempted in Linear Layout.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<MatchTheFollowingAttempted
android:layout_width="match_parent"
android:layout_height="wrap_content">

</MatchTheFollowingAttempted>

<MatchTheFollowingAttempted
android:layout_width="match_parent"
android:layout_height="wrap_content">

</MatchTheFollowingAttempted>

</LinearLayout>

</ScrollView>

</RelativeLayout>

Image_Two

When I run it real its not showing second layout.

最佳答案

目前,您正在以编程方式将 MatchTheColumnDrawView 添加到 MatchTheFollowingAttempted 而无需设置 LayoutParamsLayoutParams 有默认值,因此只要有一个 MatchTheFollowingAttempted 实例,您就很幸运了。

因此,要解决此问题,您必须将 LayoutParams 设置为 MatchTheColumnDrawView,例如:

for (int i = 0; i < numberOfOneSideButtons; i++) {

MatchTheColumnDrawView matchTheColumnDrawView = new MatchTheColumnDrawView(
mContext, leftSideButtons.get(i),
rightSideButtons.get(numberOfOneSideButtons - 1 - i),
null, null,
2.0f, MatchTheColumnDrawView.LEFT_TO_RIGHT);

RelativeLayout.LayoutParams layoutParams = new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
layoutParams.addRule(ALIGN_TOP,
leftSideButtons.get(0).getId());
layoutParams.addRule(ALIGN_BOTTOM,
leftSideButtons.get(numberOfOneSideButtons - 1).getId());
matchTheColumnDrawView.setLayoutParams(layoutParams);

matchTheColumnDrawViewArrayList.add(matchTheColumnDrawView);

addView(matchTheColumnDrawView);
}

如果您的左侧和右侧 Button 高度不同,那么您将不得不找到一个更好的公式,但想法是请求尽可能多的空间而不是整个屏幕(否则下一个自定义 View 根本不会显示),因此请尝试将 MatchTheColumnDrawView 底部与最低的 Button 底部对齐。

two custom views

附言我是怎么知道的?

在您的 View 上使用 Android Studio 的布局检查器(顺便说一句,感谢您发布完整代码!)表明“缺失的”View 实际上具有 0 的高度。

重写 MatchTheColumnDrawView 中的 onMeasure() 以记录测量的宽度和高度确认了这一点:RelativeLayout 进行两次布局:高度为0 可能会在第一遍之后发生,但在第二遍之后 View 应该有一些高度 > 0 否则它不会被显示。

编辑:

MatchTheFollowingAttempted 中,您为每个按钮设置了填充如果在计算中间高度值时减去填充,则绿色圆圈将恰好绘制在 View 边缘的中间,例如

float endViewMidHeightY = endView.getY() + endView.getHeight() / 2 - 10;

因为 Button 有自己的内边距(看起来比实际小),圆圈仍然没有覆盖可见的 Button 边缘。要实现这一点,要么使用您自己的 Button 背景,要么(有点老套,因为填充在未来的 Android 版本中可能会改变)从 x 坐标(左侧)减去填充,分别将填充添加到 x 坐标(右侧)。

下面的屏幕截图显示了一些自定义 View 和一些 Button 的示例:

enter image description here

关于android - 两个 View 之间的自定义画线无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46911682/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com