android 仿ofo页面,[Android进阶]OFO首页实现小窥

[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文件的基本格式如下:

xmlns:android="http://schemas.android.com/apk/res/android"

android:shape=""

android:useLevel="false">

android:height=""

android:width=""/>

其中根说明该文件是一个Shape资源文件,android:shape用于指定当前的形状类型,可参照下表:

图形

android:shape

矩形

rectangle

椭圆

oval

线

line

ring

用于指定Shape的宽高,用于指定shape的填充颜色,用于指定描边的相关信息,另外还有(指定圆角信息),(指定渐变信息)及(指定内部padding信息)。

扫码骑车的背景可定义为如下shape:

xmlns:android="http://schemas.android.com/apk/res/android"

android:shape="oval"

android:useLevel="false">

android:height="20dp"

android:width="20dp"/>

运行后效果如下:

[图片上传失败...(image-5867d0-1544605445241)]

更多shape细节大家可以自行尝试。

前三种实现都是将Shape做为整体的背景,思路很清晰,这里只贴出代码,不做赘述。

Shape+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">

android:layout_gravity="center_horizontal"

android:layout_marginTop="20dp"

android:src="@drawable/qr_scnner"

android:layout_width="40dp"

android:layout_height="40dp"/>

android:layout_gravity="center_horizontal"

android:gravity="center"

android:text="扫码用车"

android:layout_width="wrap_content"

android:layout_height="40dp"/>

效果如下:

[图片上传失败...(image-ac66b1-1544605445241)]

Shape+TextView

使用TextView的drawableTop属性,避免编写LinearLayout,降低渲染成本,代码如下:

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent">

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"/>

效果如下图:

[图片上传失败...(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.完整代码参见:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值