自定义View——点击更多

本文介绍了一种自定义View的实现方式——MoreView。该View可以在一段描述性文字后添加一个可点击的more区域。通过使用StaticLayout实现了多行文本显示,并通过Canvas完成了more文本的绘制。

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

网上已经有了大量的自定义View的实例,讲了很多教大家如何去写一个自定义View的。虽说本篇博文也是讲的自定义View ,但是并不会教程式的讲述如何去自定义View,

只是提供一个deom,讲述一下,并提供一下想法,仅此而已。

好了,直接上个图吧~


这个就是效果了,就是一段描述性的文字,多行显示,并且,后面有一个“more”的点击区域。

下面介绍代码吧,先是获取资源文件

 TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.MoreView);
        try{
            mText=ta.getString(R.styleable.MoreView_text);
            if(mText==null)
                throw new NullPointerException("不能为空!");
            mTextColor=ta.getColor(R.styleable.MoreView_color,getResources().getColor(R.color.colorPrimary));
            mTextSize=ta.getDimensionPixelSize(R.styleable.MoreView_textsize,20);

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            ta.recycle();
        }
这段代码,就是可以让用户在xml里面自定义的一些内容,先拿到这些内容,给好初始值。

然后就是初始化画笔部分了。

 private void init(Context context){
        mTextPaint=new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextSize(mTextSize);

        mTextPaintmore=new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mTextPaintmore.setAntiAlias(true);
        mTextPaintmore.setTextSize(mTextSize);
        mTextPaintmore.setColor(mTextColor);
        ScreenWidth=ScreenUtils.getScreenWidth(context);
    }
下面就是要onMeasure了

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize=MeasureSpec.getSize(widthMeasureSpec);
        int heightSize=MeasureSpec.getSize(heightMeasureSpec);
        int widthMode=MeasureSpec.getMode(widthMeasureSpec);
        int heightMode=MeasureSpec.getMode(heightMeasureSpec);

        int height=0;
        if(heightMode==MeasureSpec.EXACTLY){
            height=heightSize;
        }else if(heightMode==MeasureSpec.AT_MOST){
            height=800;
        }
        setMeasuredDimension(widthSize,height);
    }
这部分都不难,不需要过多解释,大家应该都能看懂

然后就是绘制部分了。onDraw()

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(!TextUtils.isEmpty(normalString)){
            canvas.save();
            layout=new StaticLayout(normalString,mTextPaint,ScreenWidth-50, Layout.Alignment.ALIGN_NORMAL
                    ,1.0F,0.0F,true);

            layout.draw(canvas);
            canvas.restore();
            layout2=new StaticLayout(normalString+mText,mTextPaintmore,ScreenWidth-50, Layout.Alignment.ALIGN_NORMAL
                    ,1.0F,0.0F,true);
            if(layout2.getLineCount()>layout.getLineCount()){
                canvas.drawText(mText,0,layout2.getHeight()-mTextPaintmore.getFontMetrics().bottom,mTextPaintmore);
            }else{
                canvas.drawText(mText,layout.getLineWidth(layout.getLineCount()-1),layout.getHeight()-mTextPaintmore.getFontMetrics().bottom,mTextPaintmore);
            }
        }
    }
这部分呢,主要是借住StaticLayout这个类,来实现多行显示。可以拿到,一段文字之后可否再加 “more” 这样的字数,或者说另起一行来绘制 "more" ,其实,总的来说,想要绘制好 "more" 主要就是找到 x ,y坐标。
canvas.drawText(mText,0,layout2.getHeight()-mTextPaintmore.getFontMetrics().bottom,mTextPaintmore);

canvas.drawText(mText,layout.getLineWidth(layout.getLineCount()-1),layout.getHeight()-mTextPaintmore.getFontMetrics().bottom,mTextPaintmore);

这个就是绘制代码。x坐标好办,如果是独立的一行就是 0,如果是跟文字同一行,就是 layout.getLineWidth(layout.getLineCount()-1),获取到最后一行的宽度就可以了。

然后 y 坐标的话,如果是独立一行的话,就是layout2的高度 减去 字体的高度,就是了,如果跟文字是同一行的话,就是layout的高度减去文字的高度就可以了。

下面就是onTouchEvent()部分了

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction()==MotionEvent.ACTION_DOWN){
            float x=event.getX();
            float y=event.getY();
            if(layout2.getLineCount()>layout.getLineCount()){ //另起一行
                if((x>=0 && x<=mTextPaintmore.measureText(mText))&&
                        (y>=layout2.getHeight()-(mTextPaintmore.getFontMetrics().descent-mTextPaintmore.getFontMetrics().ascent)
                                &&y <=layout2.getHeight())){
                    onMoreClicklistener.onClick();
                    return true;
                }
            }else{ //同一行
                if((x>=layout.getLineWidth(layout.getLineCount()-1) && x<=(layout.getLineWidth(layout.getLineCount()-1) + mTextPaintmore.measureText(mText)))
                        &&(y>=(layout.getHeight()-(mTextPaintmore.getFontMetrics().descent-mTextPaintmore.getFontMetrics().ascent))
                        &&y <=layout.getHeight())){
                    onMoreClicklistener.onClick();
                    return true;
                }
            }
        }
        return super.onTouchEvent(event);
    }
这里主要是找到,“more”的点击范围,提供onTouchEvent事件 ,return true 表示消耗此事件。

 public interface OnMoreClicklistener{
        void onClick();
    }
    private OnMoreClicklistener onMoreClicklistener;
    public void setOnMoreClicklistener(OnMoreClicklistener onMoreClicklistener){
        this.onMoreClicklistener=onMoreClicklistener;
    }
这里提供接口,供外部调用。

好了,分析就到这了。最后,送上demo链接 点击打开链接




















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值