- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试在 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>
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>
When I run it real its not showing second layout.
最佳答案
目前,您正在以编程方式将 MatchTheColumnDrawView
添加到 MatchTheFollowingAttempted
而无需设置 LayoutParams
。 LayoutParams
有默认值,因此只要有一个 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
底部对齐。
附言我是怎么知道的?
在您的 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
的示例:
关于android - 两个 View 之间的自定义画线无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46911682/
我在Windows 10中使用一些简单的Powershell代码遇到了这个奇怪的问题,我认为这可能是我做错了,但我不是Powershell的天才。 我有这个: $ix = [System.Net.Dn
var urlsearch = "http://192.168.10.113:8080/collective-intellegence/StoreClicks?userid=" + userId +
我有一个非常奇怪的问题,过去两天一直让我抓狂。 我有一个我试图控制的串行设备(LS 100 光度计)。使用设置了正确参数的终端(白蚁),我可以发送命令(“MES”),然后是定界符(CR LF),然后我
我目前正试图让无需注册的 COM 使用 Excel 作为客户端,使用 .NET dll 作为服务器。目前,我只是试图让概念验证工作,但遇到了麻烦。 显然,当我使用 Excel 时,我不能简单地使用与可
我开发了简单的 REST API - https://github.com/pavelpetrcz/MandaysFigu - 我的问题是在本地主机上,WildFly 16 服务器的应用程序运行正常。
我遇到了奇怪的情况 - 从 Django shell 创建一些 Mongoengine 对象是成功的,但是从 Django View 创建相同的对象看起来成功,但 MongoDB 中没有出现任何数据。
我是 flask 的新手,只编写了一个相当简单的网络应用程序——没有数据库,只是一个航类搜索 API 的前端。一切正常,但为了提高我的技能,我正在尝试使用应用程序工厂和蓝图重构我的代码。让它与 pus
我的谷歌分析 JavaScript 事件在开发者控制台中运行得很好。 但是当从外部 js 文件包含在页面上时,它们根本不起作用。由于某种原因。 例如; 下面的内容将在包含在控制台中时运行。但当包含在单
这是一本名为“Node.js 8 the Right Way”的书中的任务。你可以在下面看到它: 这是我的解决方案: 'use strict'; const zmq = require('zeromq
我正在阅读文本行,并创建其独特单词的列表(在将它们小写之后)。我可以使它与 flatMap 一起工作,但不能使它与 map 的“子”流一起工作。 flatMap 看起来更简洁和“更好”,但为什么 di
我正在编写一些 PowerShell 脚本来进行一些构建自动化。我发现 here echo $? 根据前面的语句返回真或假。我刚刚发现 echo 是 Write-Output 的别名。 写主机 $?
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 4年前关闭。 Improve thi
我将一个工作 View Controller 类从另一个项目复制到一个新项目中。我无法在新项目中加载 View 。在旧项目中我使用了presentModalViewController。在新版本中,我
我对 javascript 很陌生,所以很难看出我哪里出错了。由于某种原因,我的功能无法正常工作。任何帮助,将不胜感激。我尝试在外部 js 文件、头部/主体中使用它们,但似乎没有任何效果。错误要么出在
我正在尝试学习Flutter中的复选框。 问题是,当我想在Scaffold(body :)中使用复选框时,它正在工作。但我想在不同的地方使用它,例如ListView中的项目。 return Cente
我们当前使用的是 sleuth 2.2.3.RELEASE,我们看不到在 http header 中传递的 userId 字段没有传播。下面是我们的代码。 BaggageField REQUEST_I
我有一个组合框,其中包含一个项目,比如“a”。我想调用该组合框的 Action 监听器,仅在手动选择项目“a”完成时才调用。我也尝试过 ItemStateChanged,但它的工作原理与 Action
你能看一下照片吗?现在,一步前我执行了 this.interrupt()。您可以看到 this.isInterrupted() 为 false。我仔细观察——“这个”没有改变。它具有相同的 ID (1
我们当前使用的是 sleuth 2.2.3.RELEASE,我们看不到在 http header 中传递的 userId 字段没有传播。下面是我们的代码。 BaggageField REQUEST_I
我正在尝试在我的网站上设置一个联系表单,当有人点击发送时,就会运行一个作业,并在该作业中向所有管理员用户发送通知。不过,我在失败的工作表中不断收到此错误: Illuminate\Database\El
我是一名优秀的程序员,十分优秀!