最近同事需要实现如下效果的一个功能,我闲来无事就试着实现了一下,以下是具体功能的实现步骤:

功能要求:
  • 可以水平滚动
  • 动态添加个数不定
  • 可点击 点击后变为选中色

在这里插入图片描述

功能实现:
  • 自定义View
package com.light.mytext.mycustomview; 
 
import android.animation.ValueAnimator; 
import android.content.Context; 
import android.content.res.TypedArray; 
import android.graphics.Color; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.ImageView; 
import android.widget.TextView; 
 
import com.bumptech.glide.Glide; 
import com.light.mytext.R; 
import com.light.mytext.utiles.DensityUtil; 
 
import java.util.ArrayList; 
 
/** 
 * Created by HARRY on 2019/1/18 0018. 
 */ 
 
public class DiscussionAvatarView extends ViewGroup implements View.OnClickListener {
   
     
    /** 
     * 图片的宽高 
     */ 
    private int mItemViewWidth; 
    private int mItemViewHeight; 
    /** 
     * 头像间的距离 
     */ 
    private float mSpace; 
    private Context mContext; 
    private LayoutInflater mInflater; 
    /** 
     * 是否最后一个显示完全 
     */ 
    private boolean mIsLastComplete; 
    /** 
     * 最大头像数目 
     */ 
    private int mMaxCount; 
    /** 
     * 当前移动的偏移量 
     */ 
    private int mCurrentOffset; 
    /** 
     * 移动的属性动画 
     */ 
    private ValueAnimator animator; 
    /** 
     * 是否显示动画效果 
     */ 
    private boolean mIsShowAnimation; 
    /** 
     * 监听 
     */ 
    private boolean mIsShowFrame; 
    private int mFrameColor; 
    //重写点击事件 
    private OnItemViewClickListener mOnItemClickListener = null;//点击事件 
    //选中图片R.mipmap.anniu115 
    private Integer[] pic = {
   
    R.mipmap.anniu5, R.mipmap.anniu511}; 
    //选中的index 
    private int ChooseIndex = 0; 
    private ArrayList<String> listData = new ArrayList(); 
 
    public DiscussionAvatarView(Context context) {
   
     
        this(context, null); 
    } 
 
    public DiscussionAvatarView(Context context, AttributeSet attrs) {
   
     
        this(context, attrs, 0); 
    } 
 
    public DiscussionAvatarView(Context context, AttributeSet attrs, int defStyleAttr) {
   
     
        super(context, attrs, defStyleAttr); 
        initView(context, attrs); 
    } 
 
    private void initView(Context context, AttributeSet attrs) {
   
     
        this.mContext = context; 
        this.mInflater = LayoutInflater.from(mContext); 
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DiscussionAvatarView); 
        if (array != null) {
   
     
            mSpace = array.getFloat(R.styleable.DiscussionAvatarView_space, (float) 0.8); 
            mMaxCount = array.getInteger(R.styleable.DiscussionAvatarView_maxCount, 6); 
            mIsLastComplete = array.getBoolean(R.styleable.DiscussionAvatarView_isLastComplete, true); 
            mIsShowAnimation = array.getBoolean(R.styleable.DiscussionAvatarView_isShowAnimation, true); 
            mIsShowFrame = array.getBoolean(R.styleable.DiscussionAvatarView_isShowFrame, true); 
            mFrameColor = array.getColor(R.styleable.DiscussionAvatarView_frameColor, Color.RED); 
            mItemViewWidth = array.getInteger(R.styleable.DiscussionAvatarView_iviewWidth, 150);//item的宽 
            mItemViewHeight = array.getInteger(R.styleable.DiscussionAvatarView_iviewHeight, 60);//item的高 
 
            array.recycle(); 
        } 
    } 
 
    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   
     
        super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
        int heiMeasure = MeasureSpec.getSize(heightMeasureSpec); 
        int heiMode = MeasureSpec.getMode(heightMeasureSpec); 
        int widMode = MeasureSpec.getMode(widthMeasureSpec); 
        int widMeasure = MeasureSpec.getSize(widthMeasureSpec); 
 
        int wid = 0; 
        int hei = 0; 
        int count = getChildCount(); 
        for (int i = 0; i < count; i++) {
   
     
            View child = getChildAt(i); 
            LayoutParams lp = child.getLayoutParams(); 
            lp.width = DensityUtil.dip2px(mContext, mItemViewWidth); 
            lp.height = DensityUtil.dip2px(mContext, mItemViewHeight); 
            child.setLayoutParams(lp); 
            // 测量子View的宽和高,系统提供的measureChild 
            measureChild(child, widthMeasureSpec, heightMeasureSpec); 
            // 子View占据的宽度 
            int childWidth = child.getMeasuredWidth(); 
            // 子View占据的高度 
            int childHeight = child.getMeasuredHeight(); 
 
            if (i < mMaxCount) {
   
     
                if (i == 0) {
   
     
                    wid = wid + childWidth; 
                } else {
   
     
                    wid = (int) (wid + childWidth * mSpace); 
                } 
            } 
            hei = Math.max(hei, childHeight); 
            child.setOnClickListener(this); 
        } 
        //如果是exactly使用测量宽和高,否则使用自己设置的宽和高 
        setMeasuredDimension((widMode == MeasureSpec.EXACTLY) ? widMeasure : wid, 
                (heiMode == MeasureSpec.EXACTLY) ? heiMeasure : hei); 
    } 
 
 
    @Override 
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
   
     
        int count = getChildCount(); 
 
        int left = -mCurrentOffset; 
        int top = 0; 
        int right = -mCurrentOffset; 
            for (int i = count - 1; i > -1; i--) {
   
    //配合第一个元素置顶效果  数据反着放  间距也反着计算 左边叠加右边 
                View child; 
                child = getChildAt(i); 
                int childWidth = child.getMeasuredWidth(); 
                int childHeight = child.getMeasuredHeight(); 
 
                if (i == count - 1) {
   
     
                    right = right + childWidth; 
                } else {
   
     
                    right = (int) (right + childWidth * mSpace); 
                } 
                child.layout(left, top, right, childHeight); 
                left = (int) (left + childWidth * mSpace); 
            } 
    } 
 
    /** 
     * 初始化数据 
     * 
     * @param list 
     */ 
    public void initDatasList(ArrayList<String> list) {
   
     
        if (list == null) {
   
     
            return; 
        } 
        listData = list; 
        initDatas(); 
    } 
 
    /** 
     * 初始化数据 
     */ 
    public void initDatas() {
   
     
        if (listData == null) {
   
     
            return; 
        } 
        removeAllViews(); 
        int size = listData.size(); 
        mMaxCount = size; 
        for (int i = size - 1; i > -1; i--) {
   
    //反向添加 设置最左边置顶的效果 
            View view2 = mInflater.inflate(R.layout.avatar, null); 
            ImageView iv = (ImageView) view2.findViewById(R.id.imv_pic); 
            TextView tv = (TextView) view2.findViewById(R.id.tv_num); 
            tv.setText("第" + (i) + "个"); 
            if (i % 2 == 0) {
   
     
                tv.setTextColor(getResources().getColor(R.color.white)); 
            } else {
   
     
                tv.setTextColor(getResources().getColor(R.color.black)); 
            } 
            if (ChooseIndex == i) {
   
     
                Glide.with(mContext).load(R.mipmap.anniu115).into(iv); 
                tv.setTextColor(getResources().getColor(R.color.white)); 
            } else {
   
     
                Glide.with(mContext).load(pic[i % 2]).into(iv); 
            } 
            this.addView(view2); 
        } 
    } 
 
    @Override 
    public void onClick(View view) {
   
     
        int count = getChildCount(); 
        for (int i = 0; i < count; i++) {
   
     
            if (getChildAt(i).equals(view)) {
   
     
                Log.i("DiscussionAvatarView==", "点击的是第" + (count - i - 1) + "个"); 
                ChooseIndex = count - i - 1; 
                mOnItemClickListener.onViewClick(ChooseIndex); 
            } 
 
        } 
        initDatas(); 
 
    } 
 
    /** 
     * 点击事件 
     */ 
    public interface OnItemViewClickListener {
   
     
        /** 
         * 重试按钮点击 
         */ 
        void onViewClick(int poi); 
    } 
 
    /** 
     * 设置重试点击事件 
     * 
     * @param l 重试的点击事件 
     */ 
    public void setOnItemViewClickListener(OnItemViewClickListener l) {
   
     
        mOnItemClickListener = l; 
    } 
} 
 
  • 调用方法

由于要实现水平滚动,所以结合了HorizontalScrollView使用

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout 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:orientation="vertical" 
> 
 
    <HorizontalScrollView 
        android:id="@+id/scrollview" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:scrollbars="none" 
        android:layout_gravity="left"> 
 
        <com.light.mytext.mycustomview.DiscussionAvatarView 
            android:id="@+id/daview" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            app:isLastComplete="true" 
            app:isShowAnimation="false" 
            app:isShowFrame="false" 
            app:iviewHeight="48" 
            app:iviewWidth="120" 
            app:maxCount="6" 
            app:space="0.8" 
            ></com.light.mytext.mycustomview.DiscussionAvatarView> 
    </HorizontalScrollView> 
 
 
 
</LinearLayout> 
 

Java代码实现:

package com.light.mytext.mycustomview 
 
import android.os.Bundle 
import androidx.appcompat.app.AppCompatActivity 
import com.light.mytext.R 
import com.light.mytext.utiles.ToastUtils 
import kotlinx.android.synthetic.main.activity_my_pin_jie.* 
import java.util.* 
 
class MyPinJieActivity : AppCompatActivity() {
   
     
    private val mDatas = ArrayList<String>() 
    override fun onCreate(savedInstanceState: Bundle?) {
   
     
        super.onCreate(savedInstanceState) 
        setContentView(R.layout.activity_my_pin_jie) 
        initTestDatas() 
        daview.initDatasList(mDatas) 
 
 
//自动滚动到最后一个item 
        /* Timer timer=new Timer(); 
        timer.schedule(new TimerTask() { 
            @Override 
            public void run() { 
                scrollview.fullScroll(HorizontalScrollView.FOCUS_RIGHT); 
            } 
        },1000);*/ 
        daview.setOnItemViewClickListener {
   
     poi -> 
            ToastUtils.show( 
                this@MyPinJieActivity, 
                "点击的是第" + poi + "个" 
            ) 
        } 
    } 
    private fun initTestDatas() {
   
     
        for (i in 0..7) {
   
     
            mDatas.add("") 
        } 
    } 
} 
  • 资源文件
    attrs.xml
<declare-styleable name="DiscussionAvatarView"> 
        <!--头像的半径,dp为单位--> 
        <attr name="iviewWidth" format="reference|integer" /> 
        <attr name="iviewHeight" format="reference|integer" /> 
        <!--头像间的距离,为头像直径的长度的百分比,dp为单位--> 
        <attr name="space" format="reference|float" /> 
        <!--最多显示多少个头像--> 
        <attr name="maxCount" format="reference|integer" /> 
        <!--是否最后一个显示完全,默认是true--> 
        <attr name="isLastComplete" format="reference|boolean" /> 
        <!--是否显示动画效果--> 
        <attr name="isShowAnimation" format="reference|boolean" /> 
        <!--是否显示边框--> 
        <attr name="isShowFrame" format="reference|boolean" /> 
        <!--边框颜色--> 
        <attr name="frameColor" format="reference|color" /> 
    </declare-styleable> 

avatar.xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"> 
 
    <ImageView 
        android:id="@+id/imv_pic" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:background="@mipmap/anniu5" 
        android:scaleType="fitXY"></ImageView> 
 
    <TextView 
        android:id="@+id/tv_num" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="1" 
        android:textColor="#000000" 
        android:layout_centerInParent="true" 
        android:textSize="15sp" /> 
</RelativeLayout> 

评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

360度虚拟摇杆控制机器人前进后退转弯(一)