android系列教程(android开发教程 android自学入门路线)

android开发教程 android自学入门路线

1、对Android开发、对互联网感兴趣,兴趣是最好的老师,只有发自内心的感兴趣才能真正坚持下去;

2、强大的学习能力,既然自学那学习能力肯定是必备,要有很强的求知欲,持续不断的学习能力才有机会走的更远,注意,是持续不断的学习能力;

3、解决问题的能力,自学过程中肯定会遇到各种各样的坑,这个时候不要急躁,不要气馁,不要怕耗时间,一步一个脚印去解决问题,这会为你今后走上工作岗位带来极大的优势;

4、设定一个目标,比如我当初测试转行开发,自学Android的目标简单直接,因为开发比测试工资高,我转行就是为了多挣钱。我想大部分人的目标应该都跟我同感。

Android教程2020 – RecyclerView获取滑动距离

获取RecyclerView滑动的距离。

Android教程2020 – 系列总览

前面我们已经用 RecyclerView显示一些数据

本文演示如何获取RecyclerView的滑动距离。

要实现这个功能,需要给RecyclerView添加滑动时监听 RecyclerView.OnScrollListener 。

RecyclerView.OnScrollListener 是一个抽象类,我们可以选择性地实现它的方法。
onScrolled 方法的 dy 表示的是每一次y方向上的相对滑动距离。向下滑动是正数,向上滑动是负数。

可以添加一个变量来累计滑动的距离。

每次滑动都累加到 mmRvScrollY 中。
打印log

建议同时给adapter加个 registerAdapterDataObserver ,监听插入/删除/移动,自己加减前面记录的dy滚动值。

工程放这里: https://github.com/AnRFDev/Tutorial2020

Android开发教程是怎样的

参加Android开发培训的同学都会先了解Android开发教程是怎样的,下面介绍Android开发要学习并掌握的知识有:Java

Android Camera2 教程 · 第一章 · 概览

从 Android 5.0 开始,Google 引入了一套全新的相机框架 Camera2(android.hardware.camera2)并且废弃了旧的相机框架 Camera1(android.hardware.Camera)。作为一个专门从事相机应用开发的开发者来说,这一刻我等了太久了,Camera1 那寥寥无几的 API 和极差的灵活性早已不能满足日益复杂的相机功能开发。Camera2 的出现给相机应用程序带来了巨大的变革,因为它的目的是为了给应用层提供更多的相机控制权限,从而构建出更高质量的相机应用程序。本文是 Camera2 教程的开篇作,本章将介绍以下几个内容:

Camera2 的 API 模型被设计成一个 Pipeline(管道),它按顺序处理每一帧的请求并返回请求结果给客户端。下面这张来自官方的图展示了 Pipeline 的工作流程,我们会通过一个简单的例子详细解释这张图。

为了解释上面的示意图,假设我们想要同时拍摄两张不同尺寸的图片,并且在拍摄的过程中闪光灯必须亮起来。整个拍摄流程如下:

一个新的 CaptureRequest 会被放入一个被称作 Pending Request Queue 的队列中等待被执行,当 In-Flight Capture Queue 队列空闲的时候就会从 Pending Request Queue 获取若干个待处理的 CaptureRequest,并且根据每一个 CaptureRequest 的配置进行 Capture 操作。最后我们从不同尺寸的 Surface 中获取图片数据并且还会得到一个包含了很多与本次拍照相关的信息的 CaptureResult,流程结束。

相机功能的强大与否和硬件息息相关,不同厂商对 Camera2 的支持程度也不同,所以 Camera2 定义了一个叫做 Supported Hardware Level 的重要概念,其作用是将不同设备上的 Camera2 根据功能的支持情况划分成多个不同级别以便开发者能够大概了解当前设备上 Camera2 的支持情况。截止到 Android P 为止,从低到高一共有 LEGACY、LIMITED、FULL 和 LEVEL_3 四个级别:

相机的所有操作和参数配置最终都是服务于图像捕获,例如对焦是为了让某一个区域的图像更加清晰,调节曝光补偿是为了调节图像的亮度。因此,在 Camera2 里面所有的相机操作和参数配置都被抽象成 Capture(捕获),所以不要简单的把 Capture 直接理解成是拍照,因为 Capture 操作可能仅仅是为了让预览画面更清晰而进行对焦而已。如果你熟悉 Camera1,那你可能会问 setFlashMode() 在哪? setFocusMode() 在哪? takePicture() 在哪?告诉你,它们都是通过 Capture 来实现的。

Capture 从执行方式上又被细分为【单次模式】、【多次模式】和【重复模式】三种,我们来一一解释下:

CameraManager 是一个负责查询和建立相机连接的系统服务,它的功能不多,这里列出几个 CameraManager 的关键功能:

CameraCharacteristics 是一个只读的相机信息提供者,其内部携带大量的相机信息,包括代表相机朝向的 LENS_FACING ;判断闪光灯是否可用的 FLASH_INFO_AVAILABLE ;获取所有可用 AE 模式的 CONTROL_AE_AVAILABLE_MODES 等等。如果你对 Camera1 比较熟悉,那么 CameraCharacteristics 有点像 Camera1 的 Camera.CameraInfo 或者 Camera.Parameters 。

CameraDevice 代表当前连接的相机设备,它的职责有以下四个:

熟悉 Camera1 的人可能会说 CameraDevice 就是 Camera1 的 Camera 类,实则不是,Camera 类几乎负责了所有相机的操作,而 CameraDevice 的功能则十分的单一,就是只负责建立相机连接的事务,而更加细化的相机操作则交给了稍后会介绍的 CameraCaptureSession。

Surface 是一块用于填充图像数据的内存空间,例如你可以使用 SurfaceView 的 Surface 接收每一帧预览数据用于显示预览画面,也可以使用 ImageReader 的 Surface 接收 JPEG 或 YUV 数据。每一个 Surface 都可以有自己的尺寸和数据格式,你可以从 CameraCharacteristics 获取某一个数据格式支持的尺寸列表。

CameraCaptureSession 实际上就是配置了目标 Surface 的 Pipeline 实例,我们在使用相机功能之前必须先创建 CameraCaptureSession 实例。一个 CameraDevice 一次只能开启一个 CameraCaptureSession,绝大部分的相机操作都是通过向 CameraCaptureSession 提交一个 Capture 请求实现的,例如拍照、连拍、设置闪光灯模式、触摸对焦、显示预览画面等等。

CaptureRequest 是向 CameraCaptureSession 提交 Capture 请求时的信息载体,其内部包括了本次 Capture 的参数配置和接收图像数据的 Surface。CaptureRequest 可以配置的信息非常多,包括图像格式、图像分辨率、传感器控制、闪光灯控制、3A 控制等等,可以说绝大部分的相机参数都是通过 CaptureRequest 配置的。值得注意的是每一个 CaptureRequest 表示一帧画面的操作,这意味着你可以精确控制每一帧的 Capture 操作。

CaptureResult 是每一次 Capture 操作的结果,里面包括了很多状态信息,包括闪光灯状态、对焦状态、时间戳等等。例如你可以在拍照完成的时候,通过 CaptureResult 获取本次拍照时的对焦状态和时间戳。需要注意的是,CaptureResult 并不包含任何图像数据,前面我们在介绍 Surface 的时候说了,图像数据都是从 Surface 获取的。

如果要我给出强有力的理由解释为什么要使用 Camera2,那么通过 Camera2 提供的高级特性可以构建出更加高质量的相机应用程序应该是最佳理由了。

如果你熟悉 Camera1,并且打算从 Camera1 迁移到 Camera2 的话,希望以下几个建议可以对你起到帮助:

本章到此结束,主要是介绍了 Camera2 的一些基础概念,让大家能够基本了解 Camera2 的工作流程和基础概念,并且知道使用 Camera2 能够做些什么。如果你对 Camera2 还是感到很陌生,不要紧,后续的教程会带领大家逐步深入了解 Camera2。

android视频教程,哪里才有好的android视频教程

Android视频教程有非常多,以下为比较全面的在线视频教学:

  1. 百度学堂,课程很全面,用户可以免费观看学习。

  2. 极客学院,部分需要开通VIP才能观看学习。

  3. 千锋在线课堂,教程很全面,部分视频教程需要收费。

  4. 网易云课堂,部分收费。

其实大部分视频教学讲的内容都是一样的,建议完整学习完一个系列的的全部课程就够了。

1.Android recycleView万能分隔线 GridLayoutManager布局item左右间距均等(最易懂)

今天开始讲RecycleView的系列教程。分割线,分组,局部刷新,动态添加,缓存原理,抖音效果,瀑布流。嵌套,动画等等
RecyclerView的分割线是通过canvas和设置item偏移画出来的.需要知道2个方法

getItemOffsets()和onDraw方法

getItemOffsets 是针对每一个 ItemView

onDraw:遍历,进行颜色修改

我们可以看到自定义的 TestDividerItemDeoration 只实现了一个方法 getItemOffsets()。方法里面有四个参数。

Rect outRect

View view

RecyclerView parent

RecyclerView.State state

绿色区域代表 RecyclerView 中的一个 ItemView,而外面橙色区域也就是相应的 outRect,也就是 ItemView 与其它组件的偏移区域,等同于 margin 属性,通过复写 getItemOffsets() 方法,然后指定 outRect 中的 top、left、right、bottom 就可以控制各个方向的间隔了。

这实现了简单的分隔线效果,但这种方法分隔线的效果只能取决于背景色,如果我要定制分割线的颜色呢?这个时候就要 onDraw()。

————————————————

源码分析:在recycleview中的

分割线要注意,没有颜色,默认是白色的,会看不出来

第一种方案,通过

getItemOffsets()方法进行分割线!

判断是否是第一个,最后一个,是单个还是双个,是什么类型

/***

* 分割线要注意,没有颜色,默认是白色的,会看不出来

* @param outRect

* @param view

* @param parent

* @param state

*/

private void testItemOffset(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

int childAdapterPosition = parent.getChildAdapterPosition(view);

    if (childAdapterPosition ==0) {

outRect.set(0, 20, 0, 20);

    }else {

outRect.set(0, 0, 0, 20);

    }

}

第二种方案:ondraw()

@Override

public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {

super.onDraw(c, parent, state);

    int childCount = parent.getChildCount();

    for (int i =0; i 《 childCount; i++) {

View view = parent.getChildAt(i);

        int index = parent.getChildAdapterPosition(view);

        //第一个ItemView不需要绘制

        if (index ==0) {

continue;

        }

float dividerTop = view.getTop() -mDividerHeight;

        float dividerLeft = parent.getPaddingLeft();

        float dividerBottom = view.getTop();

        float dividerRight = parent.getWidth() – parent.getPaddingRight();

        c.drawRect(dividerLeft, dividerTop, dividerRight, dividerBottom, mPaint);

    }

}

 GridLayoutManager布局item左右间距均等

思路分析

首先,我们知道,对于 GridLayoutmanager ,当我们设置的 spancount 为 3 的时候,那么每个 item 的最大宽度为 itemMaxW = recycylerW / spancount = recycylerW / 3.

假设我们 spancount 为 3,那么在不设置 itemDercation 的情况下它的分布是这样的,可以看到第一列与最后一行的距离是不一样的

GridVIew出现的问题:本来固定item.高度和宽度

1.分割线有,不是理想的,左右均等

2.上下没有分割线
源码得到:

按上面分析的源码,我们可以知道,调用outRect.set(int left, int top, int right, int bottom)方法时,left一直为0,right一直为divider的宽度,而每一项item的宽度都要减去(left+right)大小,

left一直为0,right一直为divider的宽度

左上右下到底是什么的值?

计算每一个item移动的距离,左边和右边的移动距离

计算分析:

1.左边的分割线宽度为sW  (已知)

2.每个显示item的宽度,布局定义的itemWidth

3. 总共分割线宽度:totalDivider=屏幕宽度-spanCount*itemWidth

4.列之间的分割线宽度为dw   =(屏幕宽度-spanCount*item-2*sW )/(spantcount-1)

5.每个item需要留出的空间 ew=totalDivider/spanCount(即paddingLeft+paddingRight)

left:  左边的间距值(绝对值,差值)

right:右边的间距值

每个item移动的距离:

第一个Item:L0=sW                                  R0=eW-sW

第二个Item:L1=dW-R0=dW-eW+sW       R1=eW-L1=2eW-dW-sW

第三个Item:L2=dW-R1=2(dW-eW)+sW   R2=eW-L2=3eW-2dW-sW

得出公式:

Ln=(position%spanCount)*(dw-ew)+sw

Rn=ew-Ln

总结:得到3个值dw,ew, sw的值

sw:左边的距离

ew:每个的平均的分割线

dw: 列之间的分割线宽度

int firstLastSpace =50;//最左边的分割线宽度

@SuppressLint(“LongLogTag“)

@Override

public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

super.getItemOffsets(outRect, view, parent, state);

    count++;

    outRect.top =20;

    mDividerHeight =0;

    int itemWidth =dip2px(context, 100);

    int screenWidth = getScreenWidth(context);

    int dw = (screenWidth -3 * itemWidth -2 *firstLastSpace) /2;//最终计算出这个padding值

    //误区:中间的分割线的总距离,左右可能是不等的

    int totalDivder = screenWidth -3 * itemWidth;

    Log.d(“TestDividerItemDecoration“, “totalDivder“ + totalDivder);

    int eachDivder = totalDivder /3;

    int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();

    //不要用for循环

    outRect.left = (itemPosition %3) * (dw – eachDivder) +firstLastSpace;

    outRect.right = eachDivder – outRect.right;

}

错误的思路:

//误区:中间的分割线的总距离,左右可能是不等的

//不要用for循环

int firstLastSpace =50;//最左边的分割线宽度

@SuppressLint(“LongLogTag“)

@Override

public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

super.getItemOffsets(outRect, view, parent, state);

    count++;

    outRect.top =20;

    mDividerHeight =0;

    int itemWidth =dip2px(context, 100);

    int screenWidth = getScreenWidth(context);

    int padding = (screenWidth -3 * itemWidth -2 *firstLastSpace) /4;//最终计算出这个padding值

    //不能这么算,必须保证每个item的分割线一样才行。

    Log.d(“TestDividerItemDecoration“, “getItemOffsets“ +count +“item宽度:“ + itemWidth +“padding“ + padding);

    //仅仅计算左边和右边的距离

    int childCount = parent.getChildCount();

    for (int i =0; i 《 childCount; i++) {

if (i %3 ==0) {//最左边的item

            outRect.left =firstLastSpace;

            outRect.right = padding;

        }else if (i %3 ==1) {

outRect.left = padding;

            outRect.right = padding;

        }else if (i %3 ==2) {

outRect.left = padding;

            outRect.right =firstLastSpace;

        }

}

}

瀑布流的设置:

int spanIndex = layoutParams.getSpanIndex();

public class FeedDecorationextends RecyclerView.ItemDecoration {

private HomePageCardAdaptermHomePageCardAdapter;

    public FeedDecoration(HomePageCardAdapter mHomePageCardAdapter) {

this.mHomePageCardAdapter = mHomePageCardAdapter;

    }

@Override

    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {

if (mHomePageCardAdapter ==null) {

return;

        }

if (mHomePageCardAdapter.getItemViewType(parent.getChildAdapterPosition(view)) == HomePageMultipleCard.HOMEPAGE_MULTIPLE_CARD_TYPE_FITNESS_FEED) {

StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();

            int spanIndex = layoutParams.getSpanIndex();

            if (spanIndex ==0) {

outRect.set(DensityUtil.dip2px(ShadowApp.context(), 14), 0, DensityUtil.dip2px(ShadowApp.context(), 5), DensityUtil.dip2px(ShadowApp.context(), 10));

            }else {

outRect.set(DensityUtil.dip2px(ShadowApp.context(), 5), 0, DensityUtil.dip2px(ShadowApp.context(), 14), DensityUtil.dip2px(ShadowApp.context(), 10));

            }

}

}

}
demo地址: https://github.com/pengcaihua123456/shennandadao