我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

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

先上一张图看下效果:

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

主要实现功能有:

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

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

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

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

tab点击回调

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

设置预选中tab

public 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 < getChildCount(); 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 < getChildCount(); i++) {                View child = getChildAt(i);                width +=  child.getMeasuredWidth();            }            setMeasuredDimension(width, heightSize);        } else if (heightMode == MeasureSpec.AT_MOST) {            for (int i = 0; i < getChildCount(); 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 < currentIndex; i++) {            View childView = getChildAt(i);            widthOffset += childView.getMeasuredWidth() + getMargins(childView).get(0)+getMargins(childView).get(2);        }         //计算出每个子view的位置        for (int i = 0; i < counts; 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<Integer> getMargins(View view) {        LayoutParams params = (LayoutParams) view.getLayoutParams();        List<Integer> listMargin = new ArrayList<Integer>();        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();    }          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));    }         private void moveTo(View view) {        for (int i = 0; i < getChildCount(); i++) {            if (view == getChildAt(i)) {                if (i == currentIndex) {                    //不移动                    break;                } else if (i < currentIndex) {                    //向右移                    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();                }            }        }    }          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 < getChildCount() - 1) {                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怎么实现小米相机底部滑动指示器”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

这篇文章给大家分享的是有关Android怎么实现小米相机底部滑动指示器的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。先上一张图看下效果:主要实现功能有:1.支持左右滑动,每次滑动一个tab2.支持tab点击,直接
2023-06-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录