android 仿IOS实现SegmentControl

本文介绍了如何在Android中仿照iOS实现SegmentControl,通过自定义View和布局资源文件,详细讲解了实现过程,包括XML代码、自定义view代码以及在Activity中的初始化和点击事件监听。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android原本没有segment控件,如果要最简单的实现方法就用多个Button来更改背景颜色实现。

这里讲的是自定义一个控件。网上各路大牛也发过类似的。我这里也做一下记录。

美工切了个图,要实现一个这样的效果,代码大多都摘抄自网上,做了一点修改。具体原理就不多说了。

一、首先自定义资源文件xml代码如下:

<declare-styleable name="SegmentControl">
        <attr name="cornerRadius" format="dimension|reference" />
        <attr name="scv_BackgroundSelectedColor" format="reference|color" />//选中segment的背景颜色
        <attr name="scv_BackgroundNormalColor" format="reference|color" />//未选中segment的背景颜色
        <attr name="scv_TextSelectedColor" format="reference|color" />//选中segment的文字颜色
        <attr name="scv_TextNormalColor" format="reference|color" />//未选中segment的文字颜色
        <attr name="scv_FrameColor" format="reference|color" />//segment边框的颜色
        <attr name="scv_FrameWidth" format="reference|dimension" />//segment边框的宽度
        <attr name="scv_FrameCornerRadius" format="reference|dimension" />//segment四个圆角的半径大小
        <attr name="scv_TextSize" format="reference|dimension" />//文字大小
        <attr name="scv_TextArray" format="reference" />//string数组,每一个string都会填充到一个segment中
        <attr name="scv_SelectedIndex" format="reference|integer" />//默认选中的segment
        <attr name="scv_SegmentPaddingHorizontal" format="reference|dimension" />//每一个segment内部的水平padding
        <attr name="scv_SegmentPaddingVertical" format="reference|dimension" />每一个Segment的竖直方向的padding
        <attr name="scv_Gradient" format="reference|boolean" />//Segment改变时是否使用颜色渐变效果
    </declare-styleable>

二、自定义segment控件,这里用自定义view。代码如下:

package com.tang.segment.segmentcontrol;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.v4.view.ViewPager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.lang.reflect.Field;

/**
 * Created by tang on 2018/2/25.
 */

public class SegmentControl extends View {

    /**
     * onSegmentChanged function will be triggered if segment changed
     */
    public interface OnSegmentChangedListener{
        void onSegmentChanged(int newSelectedIndex);
    }

    private static final float TOUCHED_BACKGROUND_DARK_COEFFICIENT = 0.95F;

    private static final int COLOR_PRIMARY_NORMAL = 0XFFFFFFFF;
    private static final int COLOR_PRIMARY_SELECTED = 0XFF2CA99F;

    private static final int DEFAULT_COLOR_BACKGROUND_SELECTED = COLOR_PRIMARY_SELECTED;
    private static final int DEFAULT_COLOR_BACKGROUND_NORMAL = COLOR_PRIMARY_NORMAL;
    private static final int DEFAULT_COLOR_TEXT_SELECTED = COLOR_PRIMARY_NORMAL;
    private static final int DEFAULT_COLOR_TEXT_NORMAL = COLOR_PRIMARY_SELECTED;
    private static final int DEFAULT_COLOR_FRAME = COLOR_PRIMARY_SELECTED;
    private static final int DEFAULT_TEXT_SIZE_SP = 16;
    private static final int DEFAULT_FRAME_WIDTH_PX = 2;
    private static final int DEFAULT_FRAME_CORNER_RADIUS_PX = 0;
    private static final int DEFAULT_SELECTED_INDEX = 0;
    private static final int DEFAULT_SEGMENT_PADDING_HORIZONTAL = 16;
    private static final int DEFAULT_SEGMENT_PADDING_VERTICAL = 12;
    private static final boolean DEFAULT_IS_GRADIENT = false;

    private String[] mTexts = null;

    private int mColorBackgroundSelected = DEFAULT_COLOR_BACKGROUND_SELECTED;
    private int mColorBackgroundNormal = DEFAULT_COLOR_BACKGROUND_NORMAL;
    private int mColorTextSelected = DEFAULT_COLOR_TEXT_SELECTED;
    private int mColorTextNormal = DEFAULT_COLOR_TEXT_NORMAL;
    private int mColorFrame = DEFAULT_COLOR_FRAME;
    private int mFrameWidth = DEFAULT_FRAME_WIDTH_PX;
    private int mFrameCornerRadius = DEFAULT_FRAME_CORNER_RADIUS_PX;

    private int mTextSize = 0;
    private int mSelectedIndex = DEFAULT_SELECTED_INDEX;

    //used in wrap_content mode
    private int mSegmentPaddingHorizontal = DEFAULT_SEGMENT_PADDING_HORIZONTAL;
    private int mSegmentPaddingVertical = DEFAULT_SEGMENT_PADDING_VERTICAL;

    private boolean mIsGradient = DEFAULT_IS_GRADIENT;
    private OnSegmentChangedListener mOnSegmentChangedListener;

    private float unitWidth = 0;
    private Paint paintText;        //painter of the text
    private Paint paintBackground;  //painter of the background
    private Paint paintFrame;       //painter of the frame
    private RectF rectF;
    private RectF rectFArc;
    private Path pathFrame;

    private float textCenterYOffset;

    private int preTouchedIndex = -1;
    private int curTouchedIndex = -1;

    private ViewPager viewPager;

    public SegmentControl(Context context) {
        super(context);
        init();
    }
    public SegmentControl(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttr(context, attrs);
        init();
    }
    public SegmentControl(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttr(context, attrs);
        init();
    }

    private void initAttr(Context context, AttributeSet attrs) {
        if (attrs == null) {
            return;
        }

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SegmentControl);

        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);
            if(attr == R.styleable.SegmentControl_scv_BackgroundSelectedColor){
                mColorBackgroundSelected = a.getColor(attr, DEFAULT_COLOR_BACKGROUND_SELECTED);
            }else if(attr == R.styleable.SegmentControl_scv_BackgroundNormalColor){
                mColorBackgroundNormal = a.getColor(attr, DEFAULT_COLOR_BACKGROUND_NORMAL);
            }else if(attr == R.styleable.SegmentControl_scv_TextSelectedColor){
                mColorTextSelected = a.getColor(attr, DEFAULT_COLOR_TEXT_SELECTED);
            }else if(attr == R.styleable.SegmentControl_scv_TextNormalColor){
                mColorTextNormal = a.getColor(attr, DEFAULT_COLOR_TEXT_NORMAL);
            }else if(attr == R.styleable.SegmentControl_scv_FrameColor){
                mColorFrame = a.getColor(attr, DEFAULT
可自定义样式、功能全面的分段控件。项目地址:https://github.com/klongmitre/android-segmented-control-view效果图:如何使用xml中直接创建<org.mitre.ascv.AndroidSegmentedControlView         android:id="@ id/androidSegmentedControlView"         android:layout_width="match_parent"         android:layout_height="wrap_content"         ascv:ascv_defaultSelection="0"         ascv:ascv_unselectedTextColor="@color/test_attr_unselected_text_color"         ascv:ascv_selectedTextColor="@color/test_attr_selected_text_color"         ascv:ascv_selectedColor="@color/test_attr_selected_color"         ascv:ascv_unselectedColor="@color/test_attr_unselected_color"         ascv:ascv_items="@array/three_state_option"/>2. java中添加监听器,监听item的切换ascv = (AndroidSegmentedControlView)this.findViewById(R.id.androidSegmentedControlView); ascv.setIdentifier("ascv01"); //ascv.setItems(new String[]{"Test1aaaaa", "Test2", "Test3"}, new String[]{"1", "2", "3"}); ascv.setOnSelectionChangedListener(new OnSelectionChangedListener(){     @Override     public void newSelection(String identifier, String value) {//当item切换时触发  Toast.makeText(MainActivity.this, "identifier:" identifier "  value:" value, Toast.LENGTH_SHORT).show();     } });参数identifier是当有多个分段控件时,同时使用一个监听器时,用于区别是哪个触发了事件。属性说明属性名类型使用说明ascv_unselectedTextColorreference未选中的item的文字颜色ascv_unselectedColorreference未选中的item的背景颜色,不包括边框ascv_selectedColorreference选中的item背景的颜色以及边框的颜色ascv_selectedTextColorreference选中的item的文字颜色ascv_itemsreference控件item上显示的文字ascv_valuesreference控件item的值,会被传给监听器。未设置时,默认使用ascv_items。ascv_equalWidthboolean当item上的文字,即ascv_items设置的文字,长度不一致时,item的宽度是否还等长。ascv_stretchboolean是否被拉伸。即控件是否填充整个父容器。ascv_defaultSelectioninteger默认哪个item被选中,下标从0开始ascv_identifierstring控件的ID
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值