Android仿知乎日报开屏页效果

先看看知乎日报开屏页的效果,非常漂亮的开屏效果

ezgif.com-resize (2).gif

然后我来一个

ezgif.com-resize (1).gif

也不错~感觉可以以假乱真了~

很简单,直接开始。

实现这个效果先制定个三步走策略

底部布局上滑展示。 画一个知弧。 显示图片

底部布局上滑展示

直接上代码吧,属性动画基本使用

private void startAnimation() { //位移动画,从底部滑出,Y方向移动,mHeight是底部布局的高度 ObjectAnimator translationAnimator= ObjectAnimator.ofFloat(rv_bottom, "translationY", mHeight, 0f); //设置时长 translationAnimator.setDuration(1000); //透明度渐变动画 ObjectAnimator alphaAnimatorator = ObjectAnimator.ofFloat(rv_bottom, "alpha", 0f,1f); //设置时长 alphaAnimatorator.setDuration(2500); //添加监听器,位移结束后,画圆弧开始 translationAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { zhview.startAnimation(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); AnimatorSet set = new AnimatorSet(); //两个动画一起执行 set.play(translationAnimator).with(alphaAnimatorator); //go set.start(); }

在位移动画结束的时候,调用了自定义的view的方法,开始了画弧的操作。

画个知弧

接下来开始画画~ 自定义一个view,重写ondraw方法,开画之前先初始化一个合适的画笔。

private void initPaint() { mPaint1 = new Paint(); //设置画笔颜色 mPaint1.setColor(Color.WHITE); // 设置画笔的样式为圆形 mPaint1.setStrokeCap(Paint.Cap.ROUND); // 设置画笔的填充样式为描边 mPaint1.setStyle(Paint.Style.STROKE); //抗锯齿 mPaint1.setAntiAlias(true); //设置画笔宽度 mPaint1.setStrokeWidth(mBorderWidth1); mPaint2 = new Paint(); mPaint2.setColor(Color.WHITE); mPaint2.setStyle(Paint.Style.STROKE); mPaint2.setAntiAlias(true); mPaint2.setStrokeWidth(mBorderWidth2); }

mPaint1用来画弧,设置填充样式为描边,这样起码我们就能轻松画一个圆环了。其实要画的知弧就是一个圆环被啃去了一块的感觉~ 但被啃的地方很光滑,所以需要一个圆头的画笔 。
mPaint2用来画外面的圆角矩形环,设置也差不多。

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.BLACK); //矩形轮廓,圆弧在内部,给予一定的内边距 RectF rectF1 = new RectF(mBorderWidth1/2+dipToPx(8), mBorderWidth1/2+dipToPx(8), getWidth() -mBorderWidth1/2-dipToPx(8),getWidth()-mBorderWidth1/2-dipToPx(8) ); //画圆弧 参数1:矩形轮廓 参数2:起始位置 参数3:扫过的范围,初始为0 参数4:是否连接圆心 canvas.drawArc(rectF1, 90, mCurrentRadian, false, mPaint1); //矩形轮廓 RectF rectF2 = new RectF(mBorderWidth2/2,mBorderWidth2/2,getWidth()-mBorderWidth2/2,getWidth()-mBorderWidth2/2); //画圆角矩形边框 参数2 3设置x,y方向的圆角corner 都要设置 canvas.drawRoundRect(rectF2,dipToPx(8),dipToPx(8),mPaint2); }

代码量很少,但要明确环的画法,不论是画圆环还是圆角矩形环,需要先确定一个基准矩形。基准矩形的位置和大小确定环的位置和大小。画弧的方法canvas.drawArc中的参数2 3设置了开始画弧的位置和画弧的范围。看一下运行效果,圆弧的起始画点在圆心的正下方,X轴正方向为0度,所以起始画点为90度。

接下来就使用不断增大画弧的范围的方式来完成动画的实现。上代码

private void startAnimationDraw() { //圆弧扫过范围为270度 ValueAnimator valueAnimator=new ValueAnimator().ofFloat(0,270); //动画持续时间 valueAnimator.setDuration(mDuration); //设置插值器,中间快两头慢 valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); //添加状态监听器 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //不断增大圆弧扫过的范围,并重绘来实现动画效果 mCurrentRadian= (float) animation.getAnimatedValue(); invalidate(); } }); valueAnimator.start(); }

使用ValueAnimator.ofFloat创建一个值为0-270的动画,添加状态监听,在动画执行的过程中不断增大扫过的范围并重绘视图从而实现了画弧的动画效果。

整个过程就是canvas配合属性动画的方式完成了动态绘图,一点也不复杂。

显示图片

这里我使用的是Glide加载的本地图片,设置了延迟加载把握图片加载时机,获得更好的开屏效果

//延时加载图片 new Handler().postDelayed(new Runnable() { @Override public void run() { Glide.with(MainActivity.this). load(R.drawable.timg). centerCrop(). skipMemoryCache(true). diskCacheStrategy(DiskCacheStrategy.NONE). crossFade(500). into(image) ; } },2000);

这里个人认为知乎也是用某种方式预先把图片下载到本地完成来把握精确地加载时机,不知道是不是这样。。

最后贴一下代码

activity

public class MainActivity extends AppCompatActivity { private RelativeLayout rv_bottom; private Zhview zhview; private float mHeight; private ImageView image; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); rv_bottom= (RelativeLayout) this.findViewById(R.id.rv_bottom); zhview= (Zhview) this.findViewById(R.id.zhview); image= (ImageView) this.findViewById(R.id.image); rv_bottom.post(new Runnable() { @Override public void run() { //获得底部的高度 mHeight=rv_bottom.getHeight(); //开始动画 startAnimation(); //延时加载图片 new Handler().postDelayed(new Runnable() { @Override public void run() { Glide.with(MainActivity.this). load(R.drawable.timg). centerCrop(). skipMemoryCache(true). diskCacheStrategy(DiskCacheStrategy.NONE). crossFade(500). into(image) ; } },2000); } }); } private void startAnimation() { //位移动画,从底部滑出,Y方向移动 ObjectAnimator translationAnimator= ObjectAnimator.ofFloat(rv_bottom, "translationY", mHeight, 0f); //设置时长 translationAnimator.setDuration(1000); //透明度渐变动画 ObjectAnimator alphaAnimatorator = ObjectAnimator.ofFloat(rv_bottom, "alpha", 0f,1f); //设置时长 alphaAnimatorator.setDuration(2500); //添加监听器,位移结束后,画圆弧开始 translationAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { zhview.startAnimation(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); AnimatorSet set = new AnimatorSet(); //两个动画一起执行 set.play(translationAnimator).with(alphaAnimatorator); //go set.start(); } }

自定义view

public class Zhview extends View { private Paint mPaint1; //圆弧画笔 private Paint mPaint2; //外框画笔 //圆弧宽度 private int mBorderWidth1=dipToPx(5); //外框宽度 private int mBorderWidth2=dipToPx(1.5f); //扫过的范围 private float mCurrentRadian=0; //动画持续时长 private int mDuration=1500; public Zhview(Context context) { this(context,null); } public Zhview(Context context, @Nullable AttributeSet attrs) { this(context, attrs,0); } public Zhview(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //初始化画笔 initPaint(); } private void initPaint() { mPaint1 = new Paint(); //设置画笔颜色 mPaint1.setColor(Color.WHITE); // 设置画笔的样式为圆形 mPaint1.setStrokeCap(Paint.Cap.ROUND); // 设置画笔的填充样式为描边 mPaint1.setStyle(Paint.Style.STROKE); //抗锯齿 mPaint1.setAntiAlias(true); //设置画笔宽度 mPaint1.setStrokeWidth(mBorderWidth1); mPaint2 = new Paint(); mPaint2.setColor(Color.WHITE); mPaint2.setStyle(Paint.Style.STROKE); mPaint2.setAntiAlias(true); mPaint2.setStrokeWidth(mBorderWidth2); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.BLACK); //矩形轮廓,圆弧在内部,给予一定的内边距 RectF rectF1 = new RectF(mBorderWidth1/2+dipToPx(8), mBorderWidth1/2+dipToPx(8), getWidth() -mBorderWidth1/2-dipToPx(8),getWidth()-mBorderWidth1/2-dipToPx(8) ); //画圆弧 参数1:矩形轮廓 参数2:起始位置 参数3:扫过的范围,初始为0 参数4:是否连接圆心 canvas.drawArc(rectF1, 90, mCurrentRadian, false, mPaint1); //矩形轮廓 RectF rectF2 = new RectF(mBorderWidth2/2,mBorderWidth2/2,getWidth()-mBorderWidth2/2,getWidth()-mBorderWidth2/2); //画圆角矩形边框 参数2 3设置x,y方向的圆角corner 都要设置 canvas.drawRoundRect(rectF2,dipToPx(8),dipToPx(8),mPaint2); } private void startAnimationDraw() { //圆弧扫过范围为270度 ValueAnimator valueAnimator=new ValueAnimator().ofFloat(0,270); //动画持续时间 valueAnimator.setDuration(mDuration); //设置插值器,中间快两头慢 valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); //添加状态监听器 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //不断增大圆弧扫过的范围,并重绘来实现动画效果 mCurrentRadian= (float) animation.getAnimatedValue(); invalidate(); } }); valueAnimator.start(); } //开始动画 public void startAnimation(){ startAnimationDraw(); } private int dipToPx(float dip) { float density = getContext().getResources().getDisplayMetrics().density; return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1)); } }

布局文件

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black" tools:context="com.zhview.MainActivity"> <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/rv_bottom" /> <RelativeLayout android:id="@+id/rv_bottom" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:padding="20dp"> <com.zhview.Zhview android:id="@+id/zhview" android:layout_width="46dp" android:layout_height="46dp" android:layout_marginLeft="10dp" /> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_toRightOf="@+id/zhview" android:text="知乎日报" android:textColor="@android:color/white" android:textSize="19sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/zhview" android:layout_marginLeft="20dp" android:layout_toRightOf="@+id/zhview" android:text="每天三次,每次七分钟" android:textColor="@android:color/darker_gray" android:textSize="13sp" /> </RelativeLayout> </RelativeLayout>

我个人挺喜欢这些实现起来不复杂但体验非常好的设计,见到了就努力实现一下,然后边学边分享,要是跟我一样感兴趣的话可以关注我一下哦~

完整代码地址https://github.com/yanyiqun001/zhview

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-09-30 13:24:08

Android仿知乎日报开屏页效果的相关文章

Android仿知乎客户端关注和取消关注的按钮点击特效实现思路详解_Android

先说明一下,项目代码已上传至github,不想看长篇大论的也可以先去下代码,对照代码,哪里不懂点哪里. 代码在这https://github.com/zgzczzw/ZHFollowButton 前几天发现知乎关注的点击效果确实赞,查了一下实现方式,刚好看到这个问题,花了一天时间终于把这个效果实现了,现在来回答一下,很不幸,楼上各位的答案都不全对,且听我一一道来. 首先,我先详细观察了一些知乎的效果,其中有一个很神奇的地方,如图: 注意看第二张图,这个圆形在扩散的时候,圆形底下的字还在,而且新的

基于jQuery和Bootstrap框架实现仿知乎前端动态列表效果_jquery

最近基于jQuery和Bootstrap框架实现了一个仿知乎动态列表的前端效果,基本实现了和知乎动态列表相同的效果.如下: 1.基本列表项 2.列表项全文展开.折叠(图中为展开第一项) 3.评论项展开 4.列表数据加载(加载全部) 5.带动画效果的点赞功能 6.回复列表的hover显示功能 HTML代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta h

Android利用悬浮按钮实现翻页效果_Android

今天给大家分享下自己用悬浮按钮点击实现翻页效果的例子. 首先,一个按钮要实现悬浮,就要用到系统顶级窗口相关的WindowManager,WindowManager.LayoutParams.那么在AndroidManifest.xml中添加权限: <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 然后,我们要对WindowManager,WindowManager.Layout

Android 仿今日头条简单的刷新效果实例代码_Android

点击按钮,先自动进行下拉刷新,也可以手动刷新,刷新完后,最后就多一行数据.有四个选项卡. 前两天导师要求做一个给本科学生预定机房座位的app,出发点来自这里.做着做着遇到很多问题,都解决了.这个效果感觉还不错,整理一下. MainActivity package com.example.fragmentmytest; import android.content.DialogInterface; import android.graphics.Color; import android.os.B

Android利用悬浮按钮实现翻页效果

今天给大家分享下自己用悬浮按钮点击实现翻页效果的例子. 首先,一个按钮要实现悬浮,就要用到系统顶级窗口相关的WindowManager,WindowManager.LayoutParams.那么在AndroidManifest.xml中添加权限: <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 然后,我们要对WindowManager,WindowManager.Layout

Android 仿今日头条简单的刷新效果实例代码

点击按钮,先自动进行下拉刷新,也可以手动刷新,刷新完后,最后就多一行数据.有四个选项卡. 前两天导师要求做一个给本科学生预定机房座位的app,出发点来自这里.做着做着遇到很多问题,都解决了.这个效果感觉还不错,整理一下. MainActivity package com.example.fragmentmytest; import android.content.DialogInterface; import android.graphics.Color; import android.os.B

Android 使用Toolbar+DrawerLayout快速实现仿“知乎APP”侧滑导航效果

  在以前,做策划导航的时候,最常用的组件便是SlidingMenu了,当初第一次用它的时候觉得那个惊艳啊,体验可以说是非常棒. 后来,Android自己推出了一个可以实现策划导航的组件DrawerLayout,也相当的不错,更加简洁,好使.当前,很多的APP都会采用侧滑导航的设计,不仅体验上很好,而且这种为APP节省了很多"空间"的交互,给人的感觉更加舒服.  Android已经越来越追求用户体验,在APP功能越来越成熟稳定的情境下,把用户体验做到极致,是开发者应有的追求!  除了D

Android仿今日头条滑动页面导航效果_Android

最近项目中用到了滑动页面,也就是和目前市场上很火的"今日头条"页面滑动类似,在网上找了一下,大部分都是用ViewPager来实现的,刚开始我用的是ViewPager+ViewGroup,上面的标题按钮用的是HorizontalScrollView,写完之后感觉效果比较生硬,果断换掉,发现了一个效果比较好的第三方,也就是今天的主题:PagerSlidingTabStrip.好了,下面来具体介绍一下PagerSlidingTabStrip,进行一下源码解析. 一.看一下demo的样子吧 二

Android仿网易客户端顶部导航栏效果_Android

最近刚写了一个网易客户端首页导航条的动画效果,现在分享出来给大家学习学习.我说一下这个效果的核心原理.下面是效果图:          首先是布局,这个布局是我从网易客户端反编译后弄来的.大家看后应该明白,布局文件如下: <FrameLayout android:id="@id/column_navi" android:layout_width="fill_parent" android:layout_height="wrap_content&quo