android自定义数据展示view,随手指滑动实现

效果:



图像会随着手指左右移动,就这个效果,很简单。

源代码地址:

https://github.com/SunPointed/ShowDataViewDemo


思路:

重点在于对数据的处理,如果一次性把数据画完,实现滑动必然很简单。但是当数据量特别大时,一次性画完展示的却始终是屏幕大小里的数据,内存中保存了一个巨大的画布,显然行不通(我也不是很清楚,但是感觉这样做是不对的,比如有几千的数据,屏幕显示的只是10个)。那么只能每次画一部分,这样内存就不会有问题,但是现在图像随着手指滑动的事件就不那么容易处理了,当滑动超过一定距离后,必然要重新加载数据。

这里假设屏幕中展示10个数据,我们一共画14个数据,那么又分为2种情况:

1.数据量小于等于14,直接全部画出来就行。

2.数据量大于14,需要在滑动中重新加载。


步骤:

1.继承view,重写onDraw,onMeasure,onTouchEvent。在onMeasure中重新计算view的大小,见注释。


public class ShowDataView extends View {


    public ShowDataView(Context context) {
        this(context, null);
    }


    public ShowDataView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }


    public ShowDataView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        
    }


    @Override
    protected void onDraw(Canvas canvas) {
        
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec); //控件显示高度
        mScreenWidth = MeasureSpec.getSize(widthMeasureSpec);//控件显示宽度


        mDataLength = mScreenWidth * 0.55f / DATA_IN_SCREEN_NUMBER; //展示数据的宽度
        mSpaceLength = mScreenWidth * 0.45f / DATA_IN_SCREEN_NUMBER; //展示数据间空白的宽度
        mSpaceHeight = mHeight / 30; //中部折线与柱状图分界高度
        mTextHeight = mHeight / 9; //底部文字显示高度
        mAreaHeight = (mHeight - mSpaceHeight - mTextHeight) / 2; //折线图与柱状图高度
        mWidth = (mDataLength + mSpaceLength) * LIST_SIZE; //控件实际宽度
        mLength = 0; //关键变量,决定何时视图的更新
//关键变量,此处画了14个数据(14个mDataLength + mSpaceLength),始终展示中间10个
mScreenPosition = (mDataLength + mSpaceLength) * 2; setMeasuredDimension((int) mWidth, (int) mHeight);

@Override 
public void layout(int l, int t, int r, int b) { super.layout(l, t, r, b); } 
@Override 
public boolean onTouchEvent(MotionEvent event) 
{ return true; }
}


 
 

2.在ondraw中进行绘图

mDataSize = mMileList.size();
        if (mDataSize < LIST_SIZE + 1) {
            mLess14 = true;
            mSpaceLength = (mWidth - mDataLength * mDataSize) / (mDataSize + 1);
            Log.i("LQY", "mSpaceLength1->" + mSpaceLength);
            mLength = 0;
            mLeftPosition = 0;
        } else {
            mLess14 = false;
            mDataSize = LIST_SIZE;
            mMaxLeftPosition = mMileList.size() - mDataSize;
        }

        mPaint.setTextSize(mTextSize);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setStrokeWidth(mLinesWidth);

        //draw background
        mPaint.setColor(mBackColor);
        canvas.drawRect(0, 0, mWidth, mHeight, mPaint);
        mPaint.setColor(mHeightBackColor);
        canvas.drawRect(0, mAreaHeight, mWidth, mAreaHeight + mSpaceHeight, mPaint);
        canvas.drawRect(0, mAreaHeight * 2 + mSpaceHeight, mWidth, mHeight, mPaint);

        if (mMileList == null || mMileList.size() == 0) {
            // TODO: 16/2/18 paint something when there's no data
        } else {
//            int listSize = mMileList.size();
//            if (mMileList.size() < LIST_SIZE + 1) {
//                mLess14 = true;
//                mSpaceLength = (mWidth - mDataLength * listSize) / (listSize + 1);
//                mLength = 0;
//                mLeftPosition = 0;
//            } else {
//                mLess14 = false;
//                listSize = LIST_SIZE;
//                mMaxLeftPosition = mMileList.size() - listSize;
//            }
            mPaint.setColor(mBarBackColor);
            for (int i = 0; i < mDataSize; ++i) {
                canvas.drawRect(mLength + mSpaceLength + i * (mSpaceLength + mDataLength), 0, mLength + (i + 1) * (mSpaceLength + mDataLength), mAreaHeight, mPaint);
                canvas.drawRect(mLength + mSpaceLength + i * (mSpaceLength + mDataLength), mAreaHeight + mSpaceHeight, mLength + (i + 1) * (mSpaceLength + mDataLength), mAreaHeight * 2 + mSpaceHeight, mPaint);
            }

            //draw line
            mPaint.setColor(mSpeedColor);
            float maxSpeed = 0;
//            float x = 0;
//            float y = 0;
            float xx;
            float yy;
            int size = mSpeedList.size();
            for (int i = 0; i < size; ++i) {
                if (maxSpeed < mSpeedList.get(i)) {
                    maxSpeed = mSpeedList.get(i);
                }
            }

            for (int i = 0; i < mDataSize; ++i) {
                xx = mLength + mSpaceLength + i * (mSpaceLength + mDataLength) + mDataLength / 2;
                yy = mAreaHeight / 6 + (1 - mSpeedList.get(mLeftPosition + i) / maxSpeed) * mAreaHeight / 6 * 5;
                canvas.drawCircle(xx, yy, 8, mPaint);
                canvas.drawText(mDf.format(mSpeedList.get(mLeftPosition + i)), xx, yy - mAreaHeight / 48 * 3, mPaint);
//                if (i == mDataSize - 1) {
//                    canvas.drawText("速度(m/s)", xx + mDataLength, yy + mAreaHeight / 24, mPaint);
//                }
            }
            canvas.drawText("item1",  (mWidth - mScreenWidth) / 2 + mSpaceLength + 10, 40, mPaint);

            mPaint.setStyle(Paint.Style.STROKE);
            mLinePath.reset();
            mPointsX.clear();
            mPointsY.clear();
            if(mUseConner) {
                for (int i = 0; i < mDataSize; ++i) {
                    xx = mLength + mSpaceLength + i * (mSpaceLength + mDataLength) + mDataLength / 2;
                    yy = mAreaHeight / 6 + (1 - mSpeedList.get(mLeftPosition + i) / maxSpeed) * mAreaHeight / 6 * 5;
                    mPointsX.add((int) xx);
                    mPointsY.add((int) yy);
                }
                drawCurve(canvas, mPointsX, mPointsY, mLinePath, mPaint);
            } else {
                for (int i = 0; i < mDataSize; ++i) {
                    xx = mLength + mSpaceLength + i * (mSpaceLength + mDataLength) + mDataLength / 2;
                    yy = mAreaHeight / 6 + (1 - mSpeedList.get(mLeftPosition + i) / maxSpeed) * mAreaHeight / 6 * 5;
                    if (i == 0) {
                        mLinePath.moveTo(xx, yy);
                    } else {
                        mLinePath.lineTo(xx, yy);
                    }
                }
                canvas.drawPath(mLinePath, mPaint);
            }
            mPaint.setStyle(Paint.Style.FILL);

            mPaint.setColor(mHeartColor);
            float maxHeart = 0;
            size = mHeartList.size();
            for (int i = 0; i < size; ++i) {
                if (maxHeart < mHeartList.get(i)) {
                    maxHeart = mHeartList.get(i);
                }
            }
            for (int i = 0; i < mDataSize; ++i) {
                xx = mLength + mSpaceLength + i * (mSpaceLength + mDataLength) + mDataLength / 2;
                yy = mAreaHeight / 6 + (1 - mHeartList.get(mLeftPosition + i) / maxHeart) * mAreaHeight / 6 * 5;
                canvas.drawCircle(xx, yy, 8, mPaint);
                canvas.drawText(mHeartList.get(mLeftPosition + i) + "", xx, yy - mAreaHeight / 48 * 3, mPaint);
//                if (i == mDataSize - 1) {
//                    canvas.drawText("心率(t/min)", xx + mDataLength, yy + mAreaHeight / 24, mPaint);
//                }
            }
            canvas.drawText("item2", (mWidth - mScreenWidth) / 2 + mSpaceLength + 10, 80, mPaint);

 
 

3.onTouchEvent的实现

float distance = 0; //移动距离


switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        mX = event.getX();
        break;
    case MotionEvent.ACTION_MOVE:
        if (mX == 0) {
            mX = event.getX();
        }
//根据数据大小会有不同处理
        if (mLess14) {
    //小于等于14时处理很简单
            // move right
            if (mX - event.getX() < 0) {
                distance = (int) Math.abs(event.getX() - mX);
                mScreenPosition -= distance;
                if (mScreenPosition < 0) {
                    mScreenPosition = 0;
                }
                this.scrollTo((int) mScreenPosition, 0);
            }
            // move left
            else if (mX - event.getX() > 0)
            {
                distance = (int) Math.abs(event.getX() - mX);
                mScreenPosition += distance;
                if (mScreenPosition > mWidth - mScreenWidth) {
                    mScreenPosition = mWidth - mScreenWidth;
                }
                this.scrollTo((int) mScreenPosition, 0);
            }
        } else {
    //大于14的情况就复杂些了,向右滑动,左滑同理
            // move right
            if (mX - event.getX() < 0) {
                distance = (int) Math.abs(event.getX() - mX);
// 还没有滑到最右边
                if (mLeftPosition != 0) {
                    mLength += distance;
   //当mLength大于mSpaceLength+mDataLength时,将其归0,并将mLeftPosition减小1,
   //这样重绘后相当于滑动到了下一正确位置,如果不这样处理,我们的数据展示就出错了
                    if (mLength > mSpaceLength + mDataLength) {
                        mLength = 0;
                        if (mLeftPosition > 0) {
                            --mLeftPosition;
                        }
                    }
                } 
// 滑到最右边了
else{
                    mLength += distance;
                    if (mLength > 0) {
                        mLength = 0;
                    }
                }
                this.postInvalidate();
            }
            // move left
            else if (mX - event.getX() > 0) {
                distance = (int) Math.abs(event.getX() - mX);
                if (mLeftPosition != mMaxLeftPosition) {
                    mLength -= distance;


                    if (mLength < -mDataLength - mSpaceLength) {
                        mLength = 0;
                        if (mLeftPosition < mMaxLeftPosition) {
                            ++mLeftPosition;
                        }
                    }
                } else {
                    mLength -= distance;
                    if (mLength < -(mSpaceLength + mDataLength) * 2 - mSpaceLength) {
                        mLength = -(mSpaceLength + mDataLength) * 2 - mSpaceLength;
                    }
                }
                this.postInvalidate();
            }
        }
        mX = event.getX();
        break;
    case MotionEvent.ACTION_UP:
        mX = 0;
        break;
    default:
        break;
}
return true;

以上,要实现其他展示效果重写ondraw就行了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以通过自定义 RecyclerView 的 ItemDecoration 来实现手指滑动渐变调整 TextView 的文字颜色。具体步骤如下: 1. 自定义 RecyclerView 的 ItemDecoration: ```java public class TextColorItemDecoration extends RecyclerView.ItemDecoration { private int mStartColor; private int mEndColor; public TextColorItemDecoration(int startColor, int endColor) { mStartColor = startColor; mEndColor = endColor; } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager(); int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition(); int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); int totalItemCount = parent.getAdapter().getItemCount(); for (int i = firstVisibleItemPosition; i <= lastVisibleItemPosition; i++) { View view = layoutManager.findViewByPosition(i); if (view != null) { TextView textView = view.findViewById(R.id.text_view); if (textView != null) { float alpha = 1 - ((float) (i - firstVisibleItemPosition) / (lastVisibleItemPosition - firstVisibleItemPosition)); int color = (int) new ArgbEvaluator().evaluate(alpha, mStartColor, mEndColor); textView.setTextColor(color); } } } } } ``` 以上代码中,`TextColorItemDecoration` 是自定义的 RecyclerView 的 ItemDecoration,`mStartColor` 和 `mEndColor` 是起始颜色和结束颜色,`onDrawOver` 方法是 ItemDecoration 的核心方法,用于在 RecyclerView 绘制 Item 的时候进行装饰,这里是通过计算每个 TextView 的透明度,然后使用 ArgbEvaluator 进行颜色渐变计算,最后设置给 TextView 的文字颜色。 2. 在 RecyclerView 中设置 ItemDecoration: ```java int startColor = Color.RED; int endColor = Color.BLUE; recyclerView.addItemDecoration(new TextColorItemDecoration(startColor, endColor)); ``` 以上代码中,`startColor` 和 `endColor` 是起始颜色和结束颜色,使用 `TextColorItemDecoration` 对象作为参数调用 `addItemDecoration` 方法即可。 这样就可以在 RecyclerView实现手指滑动渐变调整 TextView 的文字颜色了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值