[Android进阶]OFO首页实现小窥
个人微信公众号,欢迎大家加入。
[图片上传失败...(image-81989-1544605445241)]
最近阅读量凄凄惨惨,难以为继,孤倍感无力,遂决定着眼于炫酷,造一些博眼球的东西以引流,比如说实现XXX页面效果,仿XXX页面效果等,各位看官如若觉得不错,还请动动手指点点赞,能转发一波就更好了,嘿呀,不说废话了,开撸。
做为这种博眼球系列的开篇,第一篇就从去年的共享经济着手仿制了,今天要实现的是OFO的首页页面效果,下面我们一起观察下OFO首页的页面构图:
[图片上传失败...(image-607b39-1544605445241)]
从上图我们可以看出,OFO首页整体上是一个帧布局,页面底部的操作栏遮罩在最底下的MapView上,相信大家都能写出来,唯一有疑惑的地方可能是底部的实现细节,也就是下图部分:
[图片上传失败...(image-eb719b-1544605445241)]
不考虑实现细则,结合第一张图的布局边界,我们可以做如下猜测,该部分由如下五个构建组成:
1.上弧矩形
2.向下的箭头
3.圆形的扫码用车
4.用户头像
5.铃铛
那么这五个构建该怎么用Android平台的技术实现呢?
不妨将实现方案列成如下的对应表(PS:表中的太Low,大家自己玩):
界面部分 | 实现方式1 |
---|---|
向下箭头 | ImageView/ImageButton |
用户头像 | ImageView/ImageButton |
铃铛 | ImageView/ImageButton |
那么上弧矩形和圆形的扫码用车怎么整呢?好像Android控件中并没有这样的东西,该怎么实现呢?
@[toc]
扫码用车的实现
Shape是Android中一种XML内的图形绘制方式,可以使用Shape定义圆角矩形,矩形,圆形,椭圆等形状。Shape文件的基本格式如下:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape=""
android:useLevel="false">
<solid android:color=""/>
<stroke android:width=""/>
<size
android:height=""
android:width=""/>
</shape>
其中<shape></shape>
根说明该文件是一个Shape资源文件,android:shape
用于指定当前的形状类型,可参照下表:
图形 | android:shape |
---|---|
矩形 | rectangle |
椭圆 | oval |
线 | line |
环 | ring |
<size></size>
用于指定Shape的宽高,<solid></solid>
用于指定shape的填充颜色,<stroke></stroke>
用于指定描边的相关信息,另外还有<corners></corners>
(指定圆角信息),<gradient></gradient>
(指定渐变信息)及<padding></padding>
(指定内部padding信息)。
扫码骑车的背景可定义为如下shape:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:useLevel="false">
<solid android:color="@color/colorWhite"/>
<size
android:height="20dp"
android:width="20dp"/>
</shape>
运行后效果如下:
[图片上传失败...(image-5867d0-1544605445241)]
更多shape细节大家可以自行尝试。
前三种实现都是将Shape做为整体的背景,思路很清晰,这里只贴出代码,不做赘述。
Shape+LinearLayout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@drawable/scan_image_bg"
android:layout_margin="20dp"
android:orientation="vertical">
<ImageView
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:src="@drawable/qr_scnner"
android:layout_width="40dp"
android:layout_height="40dp"/>
<TextView
android:layout_gravity="center_horizontal"
android:gravity="center"
android:text="扫码用车"
android:layout_width="wrap_content"
android:layout_height="40dp"/>
</LinearLayout>
效果如下:
[图片上传失败...(image-ac66b1-1544605445241)]
Shape+TextView
使用TextView的drawableTop属性,避免编写LinearLayout,降低渲染成本,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:background="@drawable/scan_image_bg"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:textSize="20sp"
android:paddingTop="50dp"
android:drawableTop="@drawable/qr_scnner"
android:text="扫码骑车"
android:layout_width="200dp"
android:layout_height="200dp"/>
</RelativeLayout>
效果如下图:
[图片上传失败...(image-9142b-1544605445241)]
上弧矩形的实现
图片
对于上弧矩形背景,我们肯定是能用.9图片解决问题的,这里不再赘述,关于在Android Studio内制作.9图片的方式,有需要的小伙伴可以留言,我下期推送。
自定义Drawable
除了使用.9图片我们也可以使用自定义Drawable来实现,仔细观察,我们可以发现上弧矩形和普通矩形最大的区别在于,有一边是弧形,而弧形我们可以通过贝塞尔曲线实现,这里我们只需要绘制一个填充颜色的path即可,如下图:
[图片上传失败...(image-366afc-1544605445241)]
从上图我们可以看出,绘制一个上弧矩形,关键路径有四条,A'B,BC,CD',A'D',对于A'D'而言,我们可以通过AD平分线上的控制点E决定它的弯曲程度,A',D'两点坐标可以依赖于AD两点获取,那么所有问题便都迎刃而解了,代码如下:
public class ArcBackgroundDrawable extends Drawable {
private Path mPath;
@Override
public void draw(@NonNull Canvas canvas) {
mPath = new Path();
//获取Drawable的边界
Rect bounds = getBounds();
//移动Path起点到A'处,其中AA'占AB总长度的十分之一
mPath.moveTo(bounds.left, bounds.top+(bounds.bottom-bounds.top)/10);
//绘制A'D',控制点在AD平分线上
mPath.quadTo(bounds.left+(bounds.right-bounds.left)/2 , bounds.top-(bounds.bottom-bounds.top)/10, bounds.right , bounds.top+(bounds.bottom-bounds.top)/10);
//绘制D'C
mPath.lineTo(bounds.right, bounds.bottom);
//绘制CB
mPath.lineTo(bounds.left, bounds.bottom);
//闭合曲线,自动绘制BA'
mPath.close();
//填充Path内为黄色
canvas.clipPath(mPath);
canvas.drawColor(Color.YELLOW);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
如上述步骤,我们便完成了一个上弧矩形的绘制,效果如下:
[图片上传失败...(image-d91053-1544605445241)]
自定义View
自定义View与自定义Drawable思路一致,这里不再赘述,贴出代码即可。
public class ArcBackgroundView extends View {
private float mViewWidth;
private float mViewHeight;
private int mBackgroundColor;
private Paint mArcPaint;
private Path mPath;
public ArcBackgroundView(Context context) {
super(context);
}
public ArcBackgroundView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ArcBackgroundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public ArcBackgroundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mViewWidth = w;
mViewHeight = h;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
calculatePath();
canvas.clipPath(mPath);
canvas.drawColor(mBackgroundColor);
}
private void init(Context context) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(R.styleable.ArcBackgroundView);
mBackgroundColor = typedArray.getColor(R.styleable.ArcBackgroundView_backgroundColor, Color.YELLOW);
mPath = new Path();
mArcPaint = new Paint();
mArcPaint.setColor(mBackgroundColor);
}
private void calculatePath() {
mPath.moveTo(getLeft(), getTop()+(getBottom()-getTop())/10);
mPath.quadTo(getLeft()+(getRight()-getLeft())/2 , getTop()-(getBottom()-getTop())/10, getRight() , getTop()+(getBottom()-getTop())/10);
mPath.lineTo(getRight(), getBottom());
mPath.lineTo(getLeft(), getBottom());
mPath.close();
}
}
如此则解决了所有组件的绘制问题,接下来就是使用合适的layout将这五个组件组合起来了,组合后我们就实现了OFO的首页效果,运行结果如下:
[图片上传失败...(image-c99f8a-1544605445241)]
其实我们还可以使用自定义ViewGroup,乃至于自定义View直接绘制这个底部操作栏,这里只是为大家提供一种辩证思路,希望对大家有所启发,Thanks for ur reading.完整代码参见:
https://github.com/tuozhaobing/CsdnDemoCode/tree/master/OFOPageDemo
网友评论