Android 计算位图平铺高度,使最后一项不被裁剪
问题是要创建平铺背景,该背景将以不裁剪最后一个元素的方式拉伸X轴 我想要的内容(计算每个“点”图像的高度,这样最后一块瓷砖就不会被裁剪): 我拥有的(见最后一个元素被裁剪): 应该有一种方法来创建扩展Android 计算位图平铺高度,使最后一项不被裁剪,android,android-layout,bitmap,android-custom-view,Android,Android Layout,Bitmap,Android Custom View,问题是要创建平铺背景,该背景将以不裁剪最后一个元素的方式拉伸X轴 我想要的内容(计算每个“点”图像的高度,这样最后一块瓷砖就不会被裁剪): 我拥有的(见最后一个元素被裁剪): 应该有一种方法来创建扩展ImageView或Bitmap的自定义类,并手动实现该计算。但我真的无法得到任何关于如何正确地做到这一点的信息 bg_dots.xml: <?xml version="1.0" encoding="utf-8"?> <bitmap xmlns:android="htt
ImageView
或Bitmap
的自定义类,并手动实现该计算。但我真的无法得到任何关于如何正确地做到这一点的信息
bg_dots.xml:
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_dot"
android:tileMode="repeat"/>
请查看calculateWidth()
方法
它看起来是什么样子(由于delta仍然有被裁剪的点):
我不知道如何通过
位图
/xml
实现您想要的功能,但是(正如您所想)我可以建议创建自定义类
方法允许您在中定义自定义绘图过程和
您可以计算点的正确计数/高度
您可以使用绘制单点
然后你会得到一个定制的wiget,你可以把它放在一些布局容器中(比如TextView
,而不是android:background
)
我写了一个案例,描述了一个更复杂的案例,但是你可以看到上面提到的每个方法的用法。例如,可以跳过有关路径或属性的段落
这是一个很好的例子。这可能对您也很有用,但它非常通用。如果您想在Android系统中进行自定义绘图,您应该只使用Android框架,测量和布局等工作将变得容易得多
return (int)(screenHeight * 0.07); //make it around 7 percents of screen
如果您在测量中“猜测”高度,则实际上并不是在测量视图。你需要25个点,沿着视图的宽度分布,所以这是你应该做的
窗口管理器
,显示
,等等。Android现在有分屏模式,有软导航条……屏幕大小并不重要widthMeasureSpec
包含在本例中可用宽度所需的信息。用MeasureSpec.getSize(widthmasurespec)
阅读它
现在你需要沿着这个宽度有25个点,并且分别有一个高度……所以你所需要做的就是将宽度/25
分开,你就知道你的视图应该有多高了
通过告诉框架你想要多高来完成测量
setMeasuredDimension(availableWidth, neededHeight);
布局
如果发生了变化……不管是什么原因……这里我们得到了视图的最终大小。调整您的绘图,缩放图像,计算边界
只是尽量不要做太复杂的工作,因为这可能会被称为很多
绘画
您可以通过在画布上创建一些Paint
和一些drawCircle(…)
来进行完全自定义绘图,或者您可以使用一些Drawable
。关于如何画一个点有无限的可能性
您需要它25次,因此添加一个循环,并确保沿x轴移动它。现在你准备好了
因为这是一个很难掌握的问题,这里有一个简单的例子,有一个基本的可绘制的。我还写了一篇关于测量和布局的文章。试着看看它是如何工作的(我自己喜欢在Android Studio中玩布局预览来测试我的视图!)。一旦您了解了如何测量和布局视图,剩下的就是正确缩放位图
public class DotsView extends View {
private static final int NUM_DOTS = 25;
private Drawable mDrawable;
public DotsView(Context context) {
super(context);
init();
}
public DotsView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DotsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mDrawable = new DotDrawable();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// measure where you're supposed to measure: in onMeasure
// get all of the width
// this will work with match_parent, as well as with a width of 32dp
int availableWidth = MeasureSpec.getSize(widthMeasureSpec);
// NUM_DOTS == 25, or whatever, use a constant or read into attributes
int neededHeight = (int) (availableWidth / (float) NUM_DOTS);
// apply the measure dimension to the view
setMeasuredDimension(availableWidth, neededHeight);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// called after measuring. here we know the actual size of our view
// assuming it's a square, else do some Math.min to get a valid size
int size = bottom - top;
// set the size for the drawable, maybe scale up / down, maybe center...
mDrawable.setBounds(left, top, left + size, top + size);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// get the width of this view and calculate the width used per dot
float widthPerDot = getWidth() / (float) NUM_DOTS;
// draw every single dot where it belongs.
for (int i = 0; i < NUM_DOTS; i++) {
// just redraw the same drawable and move it along the x axis
mDrawable.getBounds().offsetTo((int) ((i * widthPerDot)), 0);
// finally just draw the dot
mDrawable.draw(canvas);
}
}
public class DotDrawable extends android.graphics.drawable.Drawable {
Paint mPaint;
DotDrawable() {
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL);
}
@Override
public void draw(Canvas canvas) {
Rect bounds = getBounds();
canvas.drawCircle(bounds.centerX(), bounds.centerY(), Math.min(bounds.width(), bounds.height()) / 2, mPaint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return 0;
}
}
}
public类DotsView扩展视图{
专用静态最终int NUM_DOTS=25;
私人可提取;
公共点视图(上下文){
超级(上下文);
init();
}
公共点视图(上下文、属性集属性){
超级(上下文,attrs);
init();
}
公共点视图(上下文、属性集属性、int defStyleAttr){
super(上下文、attrs、defStyleAttr);
init();
}
私有void init(){
mDrawable=new DotDrawable();
}
@凌驾
测量时的保护空隙(内部宽度测量等级、内部高度测量等级){
//在你应该测量的地方测量:在onMeasure中
//获得所有宽度
//这将适用于match_父项,以及宽度为32dp的情况
int availableWidth=MeasureSpec.getSize(widthmasurespec);
//NUM_DOTS==25或其他任何值,使用常量或读入属性
int neededHeight=(int)(可用宽度/(浮动)点数);
//将测量尺寸标注应用于视图
设置测量尺寸(可用宽度、所需高度);
}
@凌驾
仅限受保护的空心布局(布尔值已更改、整数左侧、整数顶部、整数右侧、整数底部){
超级。仅限布局(已更改、左、上、右、下);
//测量后调用。这里我们知道视图的实际大小
//假设它是正方形,否则请执行Math.min以获得有效大小
int size=底部-顶部;
//设置可拉伸的尺寸,可能放大/缩小,可能居中。。。
mDrawable.setBounds(左、上、左+大小、上+大小);
}
@凌驾
受保护的void onDraw(画布){
super.onDraw(帆布);
//获取此视图的宽度并计算每个点使用的宽度
float widthPerDot=getWidth()/(float)NUM_DOTS;
//把每个点都画在它所属的地方。
对于(int i=0;isetMeasuredDimension(availableWidth, neededHeight);
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// called after measuring. here we know the actual size of our view
// assuming it's a square, else do some Math.min to get a valid size
int size = bottom - top;
// set the size for the drawable, maybe scale up / down, maybe center...
mDrawable.setBounds(left, top, left + size, top + size);
}
public class DotsView extends View {
private static final int NUM_DOTS = 25;
private Drawable mDrawable;
public DotsView(Context context) {
super(context);
init();
}
public DotsView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DotsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mDrawable = new DotDrawable();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// measure where you're supposed to measure: in onMeasure
// get all of the width
// this will work with match_parent, as well as with a width of 32dp
int availableWidth = MeasureSpec.getSize(widthMeasureSpec);
// NUM_DOTS == 25, or whatever, use a constant or read into attributes
int neededHeight = (int) (availableWidth / (float) NUM_DOTS);
// apply the measure dimension to the view
setMeasuredDimension(availableWidth, neededHeight);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// called after measuring. here we know the actual size of our view
// assuming it's a square, else do some Math.min to get a valid size
int size = bottom - top;
// set the size for the drawable, maybe scale up / down, maybe center...
mDrawable.setBounds(left, top, left + size, top + size);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// get the width of this view and calculate the width used per dot
float widthPerDot = getWidth() / (float) NUM_DOTS;
// draw every single dot where it belongs.
for (int i = 0; i < NUM_DOTS; i++) {
// just redraw the same drawable and move it along the x axis
mDrawable.getBounds().offsetTo((int) ((i * widthPerDot)), 0);
// finally just draw the dot
mDrawable.draw(canvas);
}
}
public class DotDrawable extends android.graphics.drawable.Drawable {
Paint mPaint;
DotDrawable() {
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL);
}
@Override
public void draw(Canvas canvas) {
Rect bounds = getBounds();
canvas.drawCircle(bounds.centerX(), bounds.centerY(), Math.min(bounds.width(), bounds.height()) / 2, mPaint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return 0;
}
}
}