带有个人资料图片对齐的按钮布局
Button Layout with Profile Picture Alignment
我想创建如图所示的按钮。在圆圈内(在 png 中是透明的)我想放置玩家的个人资料图片。蓝色条上也应该有文字。
我已经让它工作了,但它似乎太复杂了。我认为在不提供代码的情况下更容易理解我所做的事情,但如果您需要它,我可以添加它。这是布局:
- 相对布局
- LinearLayout(水平方向)
- 权重为 0.7 的空视图
- 头像权重0.2
- 权重为 0.1 的空视图
- 我在下面贴的叠加图
- LinearLayout(水平方向)
- 权重为 0.7 的 RelativeLayout(space 所有文本都可以放置的位置)
- 权重为 0.3 的空白视图
顺便说一句:圆圈右边的png不是透明的,而是白色的!
这很有效,但必须有更好的方法!所有这些只是为了将图片对齐到正确位置的空视图有点丑陋。而且覆盖图片必须位于个人资料图片和文本之间的事实使其更加难看。
我更喜欢在没有 png 作为覆盖层的情况下使用简单的形状(以便它在每个屏幕上看起来都不错)来做这件事,但我不知道该怎么做。你会推荐吗?如果是,那该怎么做?
或者您知道如何改进 xml 布局或其他方法。
非常感谢
没有图片也可以:
布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:weightSum="1.0">
<TextView
android:layout_weight="0.7"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="New Text"
android:id="@+id/textView"
android:background="#0073ff"/>
<ImageView
android:layout_weight="0.2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@drawable/half_round_drawable"
android:src="@drawable/profile"/>
</LinearLayout>
</LinearLayout>
half_round_drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="oval">
<corners android:radius="16dp" />
<solid android:color="#0073ff" />
</shape>
</item>
<item
android:bottom="0dp"
android:right="32dp"> <!-- radius *2 -->
<shape>
<solid android:color="#0073ff" />
</shape>
</item>
</layer-list>
要使个人资料图片变圆,您应该使用这样的东西:
How to create a circular ImageView in Android?
如果将背景图像限制在右侧的配置文件区域,则可以使用简单的 LinearLayout
。如果您使用九块可绘制对象,则可以在图像本身中定义内容区域,如下所示:
- 从背景图像文件中提取配置文件部分。
- 从中创建一个九补丁可绘制对象,将所有区域定义为可拉伸区域(左侧和顶部边框线),并将空圆圈定义为内容区域(右侧和底部线条)。
- 由于理想情况下您应该将图像放在前景层以确保照片不会绘制在圆圈之外,因此您可以使用
FrameLayout
和前景可绘制对象来包含个人资料照片的 ImageView
。还需要另一个虚拟子视图来解决 FrameLayout
中的 bug,这会导致 match_parent
尺寸的单个子视图布局不正确。
最后的布局应该是这样的:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#00f" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foreground="@drawable/profile_bg">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/photo"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</LinearLayout>
现在我准备好给出我的答案了。
波特雷特:
横向:
Layout.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:shape="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<!--This is the CustomView which include -->
<!--own attributes: -->
<!--circle_radius is the radius of image, -->
<!--content_padding is the padding,-->
<!--and background_color is the color of shape.-->
<CustomShape
android:layout_width="match_parent"
android:layout_height="wrap_content"
shape:circle_radius="40dp"
shape:content_padding="8dp"
shape:background_color="#FF983493">
<!--There must be two Views:-->
<!--TextView and ImageView and only in this order.-->
<!--Set-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--to bot of them, because in CustomShape it will be-->
<!--resized for you. There also don`t need to set -->
<!--any kind of margin or location attributes.-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txt"
android:padding="5dp"
android:textColor="@android:color/white"
android:text="sdsfkjsdkfhsdk flsdkfjkls asdfasd fklasdjl fkjasdklfjasd k "
android:background="@android:color/transparent"/>
<!--For RoundImage I use custom class which round the drawable,-->
<!--not a View. Look down.-->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/img"
android:src="@drawable/img"
android:scaleType="fitCenter"
android:background="@android:color/transparent" />
</CustomShape>
</RelativeLayout>
自定义形状 class:
public class CustomShape extends RelativeLayout {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
int circleRadius; // image radius
int diameter; // image diameter
int contentPadding;
int semiPadding;
int rectRightSide;
int backgroundColor;
int viewWidth; // width of parent(CustomShape layout)
public CustomShape(Context context) {
super(context);
this.setWillNotDraw(false);
}
public CustomShape(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomShape, 0, 0);
try {
this.circleRadius = (int) ta.getDimension(R.styleable.CustomShape_circle_radius, 40);
this.contentPadding = (int) ta.getDimension(R.styleable.CustomShape_content_padding, 8);
this.backgroundColor = ta.getColor(R.styleable.CustomShape_background_color, 0);
this.semiPadding = contentPadding / 2;
this.diameter = circleRadius * 2;
} finally {
ta.recycle();
}
this.setWillNotDraw(false);
}
public CustomShape(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setWillNotDraw(false);
}
@Override
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) {
super.onSizeChanged(xNew, yNew, xOld, yOld);
viewWidth = xNew;
this.rectRightSide = viewWidth - circleRadius - (circleRadius / 2); // get position for image
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
ImageView img = (ImageView) this.getChildAt(1);
RelativeLayout.LayoutParams imgParams = new LayoutParams(diameter - contentPadding, diameter - contentPadding);
imgParams.leftMargin = rectRightSide - circleRadius + semiPadding;
imgParams.topMargin = semiPadding;
img.setLayoutParams(imgParams);
//Create custom RoundImage and set to image
try {
Drawable drawable = img.getDrawable();
Bitmap bm = ((BitmapDrawable) drawable).getBitmap();
RoundImage resultImage = new RoundImage(bm);
img.setImageDrawable(resultImage);
} catch (ClassCastException e) {
}
//Positioning and resizing TextView
View txt = this.getChildAt(0);
RelativeLayout.LayoutParams txtParams = new LayoutParams(rectRightSide - circleRadius - semiPadding, diameter - contentPadding);
txtParams.topMargin = semiPadding;
txtParams.leftMargin = semiPadding;
txt.setLayoutParams(txtParams);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
this.setMeasuredDimension(parentWidth, diameter); // set correct height
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(backgroundColor);
canvas.drawRect(0, 0, rectRightSide, diameter, paint);
//Draw circle
paint.setDither(true);
canvas.drawCircle(rectRightSide, circleRadius, circleRadius, paint);
}
}
Attr.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomShape">
<attr name="circle_radius" format="dimension" />
<attr name="content_padding" format="dimension" />
<attr name="background_color" format="color" />
</declare-styleable>
</resources>
圆图class:
public class RoundImage extends Drawable {
private final Bitmap mBitmap;
private final Paint mPaint;
private final RectF mRectF;
private final int mBitmapWidth;
private final int mBitmapHeight;
public RoundImage(Bitmap bitmap) {
mBitmap = bitmap;
mRectF = new RectF();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(shader);
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
}
@Override
public void draw(Canvas canvas) {
canvas.drawOval(mRectF, mPaint);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRectF.set(bounds);
}
@Override
public void setAlpha(int alpha) {
if (mPaint.getAlpha() != alpha) {
mPaint.setAlpha(alpha);
invalidateSelf();
}
}
@Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}
@Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}
public void setAntiAlias(boolean aa) {
mPaint.setAntiAlias(aa);
invalidateSelf();
}
@Override
public void setFilterBitmap(boolean filter) {
mPaint.setFilterBitmap(filter);
invalidateSelf();
}
@Override
public void setDither(boolean dither) {
mPaint.setDither(dither);
invalidateSelf();
}
public Bitmap getBitmap() {
return mBitmap;
}
}
希望对您有所帮助。
我想创建如图所示的按钮。在圆圈内(在 png 中是透明的)我想放置玩家的个人资料图片。蓝色条上也应该有文字。 我已经让它工作了,但它似乎太复杂了。我认为在不提供代码的情况下更容易理解我所做的事情,但如果您需要它,我可以添加它。这是布局:
- 相对布局
- LinearLayout(水平方向)
- 权重为 0.7 的空视图
- 头像权重0.2
- 权重为 0.1 的空视图
- 我在下面贴的叠加图
- LinearLayout(水平方向)
- 权重为 0.7 的 RelativeLayout(space 所有文本都可以放置的位置)
- 权重为 0.3 的空白视图
- LinearLayout(水平方向)
顺便说一句:圆圈右边的png不是透明的,而是白色的!
这很有效,但必须有更好的方法!所有这些只是为了将图片对齐到正确位置的空视图有点丑陋。而且覆盖图片必须位于个人资料图片和文本之间的事实使其更加难看。
我更喜欢在没有 png 作为覆盖层的情况下使用简单的形状(以便它在每个屏幕上看起来都不错)来做这件事,但我不知道该怎么做。你会推荐吗?如果是,那该怎么做?
或者您知道如何改进 xml 布局或其他方法。
非常感谢
没有图片也可以:
布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:weightSum="1.0">
<TextView
android:layout_weight="0.7"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="New Text"
android:id="@+id/textView"
android:background="#0073ff"/>
<ImageView
android:layout_weight="0.2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@drawable/half_round_drawable"
android:src="@drawable/profile"/>
</LinearLayout>
</LinearLayout>
half_round_drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="oval">
<corners android:radius="16dp" />
<solid android:color="#0073ff" />
</shape>
</item>
<item
android:bottom="0dp"
android:right="32dp"> <!-- radius *2 -->
<shape>
<solid android:color="#0073ff" />
</shape>
</item>
</layer-list>
要使个人资料图片变圆,您应该使用这样的东西: How to create a circular ImageView in Android?
如果将背景图像限制在右侧的配置文件区域,则可以使用简单的 LinearLayout
。如果您使用九块可绘制对象,则可以在图像本身中定义内容区域,如下所示:
- 从背景图像文件中提取配置文件部分。
- 从中创建一个九补丁可绘制对象,将所有区域定义为可拉伸区域(左侧和顶部边框线),并将空圆圈定义为内容区域(右侧和底部线条)。
- 由于理想情况下您应该将图像放在前景层以确保照片不会绘制在圆圈之外,因此您可以使用
FrameLayout
和前景可绘制对象来包含个人资料照片的ImageView
。还需要另一个虚拟子视图来解决FrameLayout
中的 bug,这会导致match_parent
尺寸的单个子视图布局不正确。
最后的布局应该是这样的:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#00f" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foreground="@drawable/profile_bg">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/photo"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</LinearLayout>
现在我准备好给出我的答案了。
波特雷特:
横向:
Layout.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:shape="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<!--This is the CustomView which include -->
<!--own attributes: -->
<!--circle_radius is the radius of image, -->
<!--content_padding is the padding,-->
<!--and background_color is the color of shape.-->
<CustomShape
android:layout_width="match_parent"
android:layout_height="wrap_content"
shape:circle_radius="40dp"
shape:content_padding="8dp"
shape:background_color="#FF983493">
<!--There must be two Views:-->
<!--TextView and ImageView and only in this order.-->
<!--Set-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--to bot of them, because in CustomShape it will be-->
<!--resized for you. There also don`t need to set -->
<!--any kind of margin or location attributes.-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txt"
android:padding="5dp"
android:textColor="@android:color/white"
android:text="sdsfkjsdkfhsdk flsdkfjkls asdfasd fklasdjl fkjasdklfjasd k "
android:background="@android:color/transparent"/>
<!--For RoundImage I use custom class which round the drawable,-->
<!--not a View. Look down.-->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/img"
android:src="@drawable/img"
android:scaleType="fitCenter"
android:background="@android:color/transparent" />
</CustomShape>
</RelativeLayout>
自定义形状 class:
public class CustomShape extends RelativeLayout {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
int circleRadius; // image radius
int diameter; // image diameter
int contentPadding;
int semiPadding;
int rectRightSide;
int backgroundColor;
int viewWidth; // width of parent(CustomShape layout)
public CustomShape(Context context) {
super(context);
this.setWillNotDraw(false);
}
public CustomShape(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomShape, 0, 0);
try {
this.circleRadius = (int) ta.getDimension(R.styleable.CustomShape_circle_radius, 40);
this.contentPadding = (int) ta.getDimension(R.styleable.CustomShape_content_padding, 8);
this.backgroundColor = ta.getColor(R.styleable.CustomShape_background_color, 0);
this.semiPadding = contentPadding / 2;
this.diameter = circleRadius * 2;
} finally {
ta.recycle();
}
this.setWillNotDraw(false);
}
public CustomShape(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setWillNotDraw(false);
}
@Override
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) {
super.onSizeChanged(xNew, yNew, xOld, yOld);
viewWidth = xNew;
this.rectRightSide = viewWidth - circleRadius - (circleRadius / 2); // get position for image
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
ImageView img = (ImageView) this.getChildAt(1);
RelativeLayout.LayoutParams imgParams = new LayoutParams(diameter - contentPadding, diameter - contentPadding);
imgParams.leftMargin = rectRightSide - circleRadius + semiPadding;
imgParams.topMargin = semiPadding;
img.setLayoutParams(imgParams);
//Create custom RoundImage and set to image
try {
Drawable drawable = img.getDrawable();
Bitmap bm = ((BitmapDrawable) drawable).getBitmap();
RoundImage resultImage = new RoundImage(bm);
img.setImageDrawable(resultImage);
} catch (ClassCastException e) {
}
//Positioning and resizing TextView
View txt = this.getChildAt(0);
RelativeLayout.LayoutParams txtParams = new LayoutParams(rectRightSide - circleRadius - semiPadding, diameter - contentPadding);
txtParams.topMargin = semiPadding;
txtParams.leftMargin = semiPadding;
txt.setLayoutParams(txtParams);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
this.setMeasuredDimension(parentWidth, diameter); // set correct height
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(backgroundColor);
canvas.drawRect(0, 0, rectRightSide, diameter, paint);
//Draw circle
paint.setDither(true);
canvas.drawCircle(rectRightSide, circleRadius, circleRadius, paint);
}
}
Attr.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomShape">
<attr name="circle_radius" format="dimension" />
<attr name="content_padding" format="dimension" />
<attr name="background_color" format="color" />
</declare-styleable>
</resources>
圆图class:
public class RoundImage extends Drawable {
private final Bitmap mBitmap;
private final Paint mPaint;
private final RectF mRectF;
private final int mBitmapWidth;
private final int mBitmapHeight;
public RoundImage(Bitmap bitmap) {
mBitmap = bitmap;
mRectF = new RectF();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(shader);
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
}
@Override
public void draw(Canvas canvas) {
canvas.drawOval(mRectF, mPaint);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRectF.set(bounds);
}
@Override
public void setAlpha(int alpha) {
if (mPaint.getAlpha() != alpha) {
mPaint.setAlpha(alpha);
invalidateSelf();
}
}
@Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}
@Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}
public void setAntiAlias(boolean aa) {
mPaint.setAntiAlias(aa);
invalidateSelf();
}
@Override
public void setFilterBitmap(boolean filter) {
mPaint.setFilterBitmap(filter);
invalidateSelf();
}
@Override
public void setDither(boolean dither) {
mPaint.setDither(dither);
invalidateSelf();
}
public Bitmap getBitmap() {
return mBitmap;
}
}
希望对您有所帮助。