Android怎么实现小米相机底部滑动指示器

发布时间:2021-04-15 14:39:38

来源:亿速云

阅读:94

作者:小新

这篇文章给大家分享的是有关Android怎么实现小米相机底部滑动指示器的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

先上一张图看下效果:

主要实现功能有:

1.支持左右滑动,每次滑动一个tab

2.支持tab点击,直接跳到对应tab

3.选中的tab一直处于居中位置

4.支持部分UI自定义(大家可根据需要自己改动)

5.tab点击回调

6.内置Tab接口,放入的内容需要实现Tab接口

7.设置预选中tabpublic class CameraIndicator extends LinearLayout {

// 当前选中的位置索引

private int currentIndex;

//tabs集合

private Tab[] tabs;

// 利用Scroller类实现最终的滑动效果

public Scroller mScroller;

//滑动执行时间(ms)

private int mDuration = 300;

//选中text的颜色

private int selectedTextColor = 0xffffffff;

//未选中的text的颜色

private int normalTextColor = 0xffffffff;

//选中的text的背景

private Drawable selectedTextBackgroundDrawable;

private int selectedTextBackgroundColor;

private int selectedTextBackgroundResources;

//是否正在滑动

private boolean isScrolling = false;

private int onLayoutCount = 0;

public CameraIndicator(Context context) {

this(context, null);

}

public CameraIndicator(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public CameraIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

mScroller = new Scroller(context);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int widthMode = MeasureSpec.getMode(widthMeasureSpec);

int widthSize = MeasureSpec.getSize(widthMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

int heightSize = MeasureSpec.getSize(heightMeasureSpec);

//测量所有子元素

measureChildren(widthMeasureSpec, heightMeasureSpec);

//处理wrap_content的情况

int width = 0;

int height = 0;

if (getChildCount() == 0) {

setMeasuredDimension(0, 0);

} else if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {

for (int i = 0; i

View child = getChildAt(i);

width +=  child.getMeasuredWidth();

height = Math.max(height, child.getMeasuredHeight());

}

setMeasuredDimension(width, height);

} else if (widthMode == MeasureSpec.AT_MOST) {

for (int i = 0; i

View child = getChildAt(i);

width +=  child.getMeasuredWidth();

}

setMeasuredDimension(width, heightSize);

} else if (heightMode == MeasureSpec.AT_MOST) {

for (int i = 0; i

View child = getChildAt(i);

height = Math.max(height, child.getMeasuredHeight());

}

setMeasuredDimension(widthSize, height);

} else {

//如果自定义ViewGroup之初就已确认该ViewGroup宽高都是match_parent,那么直接设置即可

setMeasuredDimension(widthSize, heightSize);

}

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

//给选中text的添加背景会多次进入onLayout,会导致位置有问题,暂未解决

if (onLayoutCount > 0) {

return;

}

onLayoutCount++;

int counts = getChildCount();

int childLeft = 0;

int childRight = 0;

int childTop = 0;

int childBottom = 0;

//居中显示

int widthOffset = 0;

//计算最左边的子view距离中心的距离

for (int i = 0; i

View childView = getChildAt(i);

widthOffset += childView.getMeasuredWidth() + getMargins(childView).get(0)+getMargins(childView).get(2);

}

//计算出每个子view的位置

for (int i = 0; i

View childView = getChildAt(i);

childView.setOnClickListener(v -> moveTo(v));

if (i != 0) {

View preView = getChildAt(i - 1);

childLeft = preView.getRight() +getMargins(preView).get(2)+ getMargins(childView).get(0);

} else {

childLeft = (getWidth() - getChildAt(currentIndex).getMeasuredWidth()) / 2 - widthOffset;

}

childRight = childLeft + childView.getMeasuredWidth();

childTop = (getHeight() - childView.getMeasuredHeight()) / 2;

childBottom = (getHeight() + childView.getMeasuredHeight()) / 2;

childView.layout(childLeft, childTop, childRight, childBottom);

}

TextView indexText = (TextView) getChildAt(currentIndex);

changeSelectedUIState(indexText);

}

private List getMargins(View view) {

LayoutParams params = (LayoutParams) view.getLayoutParams();

List listMargin = new ArrayList();

listMargin.add(params.leftMargin);

listMargin.add(params.topMargin);

listMargin.add(params.rightMargin);

listMargin.add(params.bottomMargin);

return listMargin;

}

@Override

public void computeScroll() {

if (mScroller.computeScrollOffset()) {

// 滑动未结束,内部使用scrollTo方法完成实际滑动

scrollTo(mScroller.getCurrX(), mScroller.getCurrY());

invalidate();

} else {

//滑动完成

isScrolling = false;

if (listener != null) {

listener.onChange(currentIndex,tabs[currentIndex]);

}

}

super.computeScroll();

}

/**

* 改变选中TextView的颜色

*

* @param currentIndex 滑动之前选中的那个

* @param nextIndex    滑动之后选中的那个

*/

public final void scrollToNext(int currentIndex, int nextIndex) {

TextView selectedText = (TextView) getChildAt(currentIndex);

if (selectedText != null) {

selectedText.setTextColor(normalTextColor);

selectedText.setBackground(null);

}

selectedText = (TextView) getChildAt(nextIndex);

if (selectedText != null) {

changeSelectedUIState(selectedText);

}

}

private void changeSelectedUIState(TextView view) {

view.setTextColor(selectedTextColor);

if (selectedTextBackgroundDrawable != null) {

view.setBackground(selectedTextBackgroundDrawable);

}

if (selectedTextBackgroundColor != 0) {

view.setBackgroundColor(selectedTextBackgroundColor);

}

if (selectedTextBackgroundResources != 0) {

view.setBackgroundResource(selectedTextBackgroundResources);

}

}

/**

* 向右滑一个

*/

public void moveToRight() {

moveTo(getChildAt(currentIndex - 1));

}

/**

* 向左滑一个

*/

public void moveToLeft() {

moveTo(getChildAt(currentIndex + 1));

}

/**

* 滑到目标view

*

* @param view 目标view

*/

private void moveTo(View view) {

for (int i = 0; i

if (view == getChildAt(i)) {

if (i == currentIndex) {

//不移动

break;

} else if (i

//向右移

if (isScrolling) {

return;

}

isScrolling = true;

int dx = getChildAt(currentIndex).getLeft() - view.getLeft() + (getChildAt(currentIndex).getMeasuredWidth() - view.getMeasuredWidth()) / 2;

//这里使用scroll会使滑动更平滑不卡顿,scroll会根据起点、终点及时间计算出每次滑动的距离,其内部有一个插值器

mScroller.startScroll(getScrollX(), 0, -dx, 0, mDuration);

scrollToNext(currentIndex, i);

setCurrentIndex(i);

invalidate();

} else if (i > currentIndex) {

//向左移

if (isScrolling) {

return;

}

isScrolling = true;

int dx = view.getLeft() - getChildAt(currentIndex).getLeft() + (view.getMeasuredWidth() - getChildAt(currentIndex).getMeasuredWidth()) / 2;

mScroller.startScroll(getScrollX(), 0, dx, 0, mDuration);

scrollToNext(currentIndex, i);

setCurrentIndex(i);

invalidate();

}

}

}

}

/**

* 设置tabs

*

* @param tabs

*/

public void setTabs(Tab... tabs) {

this.tabs = tabs;

//暂时不通过layout布局添加textview

if (getChildCount()>0){

removeAllViews();

}

for (Tab tab : tabs) {

TextView textView = new TextView(getContext());

textView.setText(tab.getText());

textView.setTextSize(14);

textView.setTextColor(selectedTextColor);

textView.setPadding(dp2px(getContext(),5), dp2px(getContext(),2), dp2px(getContext(),5),dp2px(getContext(),2));

LayoutParams layoutParams= new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);

layoutParams.rightMargin=dp2px(getContext(),2.5f);

layoutParams.leftMargin=dp2px(getContext(),2.5f);

textView.setLayoutParams(layoutParams);

addView(textView);

}

}

public int getCurrentIndex() {

return currentIndex;

}

//设置默认选中第几个

public void setCurrentIndex(int currentIndex) {

this.currentIndex = currentIndex;

}

//设置滑动时间

public void setDuration(int mDuration) {

this.mDuration = mDuration;

}

public void setSelectedTextColor(int selectedTextColor) {

this.selectedTextColor = selectedTextColor;

}

public void setNormalTextColor(int normalTextColor) {

this.normalTextColor = normalTextColor;

}

public void setSelectedTextBackgroundDrawable(Drawable selectedTextBackgroundDrawable) {

this.selectedTextBackgroundDrawable = selectedTextBackgroundDrawable;

}

public void setSelectedTextBackgroundColor(int selectedTextBackgroundColor) {

this.selectedTextBackgroundColor = selectedTextBackgroundColor;

}

public void setSelectedTextBackgroundResources(int selectedTextBackgroundResources) {

this.selectedTextBackgroundResources = selectedTextBackgroundResources;

}

public interface OnSelectedChangedListener {

void onChange(int index, Tab tag);

}

private OnSelectedChangedListener listener;

public void setOnSelectedChangedListener(OnSelectedChangedListener listener) {

if (listener != null) {

this.listener = listener;

}

}

private int dp2px(Context context, float dpValue) {

DisplayMetrics metrics = context.getResources().getDisplayMetrics();

return (int) (metrics.density * dpValue + 0.5F);

}

public interface Tab{

String getText();

}

private float startX = 0f;

@Override

public boolean onTouchEvent(MotionEvent event) {

if (event.getAction() == MotionEvent.ACTION_DOWN) {

startX = event.getX();

}

if (event.getAction() == MotionEvent.ACTION_UP) {

float endX = event.getX();

//向左滑条件

if (endX - startX > 50 && currentIndex > 0) {

moveToRight();

}

if (startX - endX > 50 && currentIndex

moveToLeft();

}

}

return true;

}

@Override

public boolean onInterceptTouchEvent(MotionEvent event) {

if (event.getAction() == MotionEvent.ACTION_DOWN) {

startX = event.getX();

}

if (event.getAction() == MotionEvent.ACTION_UP) {

float endX = event.getX();

//向左滑条件

if (Math.abs(startX-endX)>50){

onTouchEvent(event);

}

}

return super.onInterceptTouchEvent(event);

}

}

在Activity或fragment中使用private var tabs = listOf("慢动作", "短视频", "录像", "拍照", "108M", "人像", "夜景", "萌拍", "全景", "专业")

lateinit var  imageAnalysis:ImageAnalysis

override fun initView() {

//实现了CameraIndicator.Tab的对象

val map = tabs.map {

CameraIndicator.Tab { it }

}?.toTypedArray() ?: arrayOf()

//将tab集合设置给cameraIndicator,(binding.cameraIndicator即xml布局里的控件)

binding.cameraIndicator.setTabs(*map)

//默认选中  拍照

binding.cameraIndicator.currentIndex = 3

//点击某个tab的回调

binding.cameraIndicator.setSelectedTextBackgroundResources(R.drawable.selected_text_bg)

binding.cameraIndicator.setOnSelectedChangedListener { index, tag ->

Toast.makeText(this,tag.text,Toast.LENGTH_SHORT).show()

}

}

感谢各位的阅读!关于“Android怎么实现小米相机底部滑动指示器”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

android camera滑动,Android怎么实现小米相机底部滑动指示器相关推荐

  1. android camera 分辨率,Android:相机帧分辨率大于640x480(Android: camera frame resolution larger than 640x480)...

    Android:相机帧分辨率大于640x480(Android: camera frame resolution larger than 640x480) 在Android中,您需要将Surface设 ...

  2. android camera入门,android 基础一 Camera1 预览、拍照

    预览流程: Camera.open-->camera.setPreviewDisplay->camera.startPreview 拍照:camera.takePicture-->保 ...

  3. android camera fragment,Android Camera 模块分析(三)

    第三部分 Camera的主要实现分析 3.1 JAVA程序部分 在packages/apps/Camera/src/com/android/camera/ 目录的Camera.java文件中,包含了对 ...

  4. Android仿滴滴首页上拉,仿照滴滴打车底部滑动条

    [实例简介] 仿照滴滴打车底部滑动条,代码详情 [实例截图] [核心代码] 仿滴滴打车滑动条 └── 仿滴滴打车滑动条 ├── AndroidManifest.xml ├── bin │   ├── ...

  5. android camera 废弃,Android相机android.hardware.Camera已弃用

    API文档 根据Android开发人员指南CameraSupport,他们说: 我们建议将新的android.hardware.camera2 API用于新的应用程序. 在关于CameraSuppor ...

  6. android camera 动画,android高仿小米时钟(使用Camera和Matrix实现3D效果)

    继续练习自定义View..毕竟熟才能生巧.一直觉得小米的时钟很精美,那这次就搞它~这次除了练习自定义View,还涉及到使用Camera和Matrix实现3D效果. 一个这样的效果,在绘制的时候最好选择 ...

  7. android camera工程师,Android从Camera中获取图片的两种方法

    方法一: 此方法会由Camera直接产生照片回传给应用程序,但是返回的是压缩图片,显示不清晰 /**   启动Camera */ private void intentCamera(){ try { ...

  8. android camera 动画,Android 使用Camera创建3D动画

    在Android中,可以使用android.graphics.Camera这个类进行3D变换 之前更改CameraUI的时候,需要做一个切换前后摄像头的翻转动画,刚开始在网上着了一些翻转动画的代码,合 ...

  9. android camera autofocus,android – autoFocus抛出异常

    我已经尝试了一切,但我仍然无法解决这个问题. 我正在一个应用程序中实现相机功能,一切都可以正常工作,除了自动对焦.当我调用autoFocus()时,它会引发一个异常,我不明白为什么.我正在运行Desi ...

最新文章

  1. JavaScript高级程序设计(第3版)非扫描版
  2. python读取 pcd 数据 三种方法
  3. Visifire Silverlight Charts (基于SilverLight的Chart组件)
  4. jmeter压测之 监控--nmon
  5. Fragment 横竖屏切换问题
  6. android服务器 性能,Android性能优化(中)
  7. 漏洞扫描技术:对Web应用程序进行漏洞扫描
  8. SQL Server实现列转行
  9. android 自定义曲线图,Android自定义View——贝赛尔曲线
  10. c++:ISBN号码
  11. 利用Exchange服务同步iOS和android中的联系人
  12. Tribler for Mac(BT资源搜索下载器)
  13. 乔戈里推荐的新版Java学习路线,开源!
  14. Excel文档误删的4种恢复方法,1秒就可以还原所有内容,你用过吗
  15. Android androidx.startup:startup-runtime的minCompileSdk问题
  16. 题目分析参考贺老师的答案————谁是小偷如何派任务
  17. 【贪玩巴斯】带你一起攻克英语语法长难句—— 第二章——并列句全解 2021年12月17日——2022年2月5日
  18. 戴姆勒与Infosys结成战略合作伙伴关系,推动创新及IT基础设施转型
  19. STC+Andriod+ESP8266制作手机遥控小车
  20. 1610: DNA序列---变异问题 - 模拟

热门文章

  1. android 闪存软件测试,手机为什么这么卡:闪存I/O测试AndroBench
  2. python怎么测试c代码_如何正确测试python中的C-API,C-API返回错误代码
  3. linux中ls文件内存大小,Linux下用ls和du命令查看文件以及文件夹大小
  4. php prepare 批量,PreparedStatement批处理
  5. mysql-5.5.56配置_mysql 5.5.56免安装版配置方法
  6. hdu3339 In Action(Dijkstra+01背包)
  7. 滤镜怎么调_手机、电脑怎么剪辑视频?真心求推荐实用工具
  8. java properties用法_java中Properties文件加载和使用方法
  9. oracle标量子查询的优势,标量子查询
  10. 远程过程调用失败_Java开发大型互联网RPC远程调用服务实现之问题处理方案