android-自定义控件基础

为什么需要自定义控件?

由于安卓系统控件提供的属性和api不足以满足项目需求中要求的效果时,通常需要采用自定义控件的方式来完成需求(貌似有点简洁,不过应该是说道了重点吧)

自定义控件分为哪几种?

1.组合控件

  采用Linearlayout,RelativeLayout,FrameLayout加上自定义xml所形成的view,下面是一段举例代码

 

package tv.douyu.newpk;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.LinearInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.douyu.lib.utils.DYDensityUtils;
import com.douyu.lib.utils.DYNumberUtils;
import com.douyu.module.link.R;
import com.orhanobut.logger.MasterLog;

import tv.douyu.utils.LinkPkHelper;

public class UnPkProgress extends FrameLayout {

    public UnPkProgress(@NonNull Context context) {
        this(context, null);
    }

    public UnPkProgress(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public UnPkProgress(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }


    private LinearLayout li;
    private TextView tvLeft;
    private TextView tvRight;
    private TextView homeProgressValue;
    private TextView guestProgressValue;

    private ImageView ivFlashLeft;
    private ImageView ivFlashRight;

    private  boolean hasLeft;
    private  boolean hasRight;


    private void initView() {
        View.inflate(getContext(), R.layout.view_un_pk_progress, this);
        li = findViewById(R.id.un_pk_pr_li);
        tvLeft = findViewById(R.id.left_progress);
        tvRight = findViewById(R.id.right_progress);
        homeProgressValue = findViewById(R.id.home_progress_value);
        guestProgressValue = findViewById(R.id.guest_progress_value);
        ivFlashLeft = findViewById(R.id.iv_flash_left);
        ivFlashRight = findViewById(R.id.iv_flash_right);

    }

    public void updateProgress(final String sc, final String sc1) {
        tvLeft.setBackgroundResource(R.drawable.bg_gradient_up_red);
        tvRight.setBackgroundResource(R.drawable.bg_gradient_up_blue);

        li.post(new Runnable() {
            @Override
            public void run() {
                long left = DYNumberUtils.parseLongByCeil(sc) / 100;
                long right = DYNumberUtils.parseLongByCeil(sc1) / 100;
                long total = left + right;
                float lw = (float) left / total;
                float rw = (float) right / total;
                int tw = li.getWidth();
                if (tw == 0) {
                    tw = DYDensityUtils.dip2px(224);//UI给的固定长度
                }
                if (left == 0 && right == 0) {
                    tvLeft.setLayoutParams(new LinearLayout.LayoutParams(tw / 2, LayoutParams.MATCH_PARENT));
                    tvRight.setLayoutParams(new LinearLayout.LayoutParams(tw / 2, LayoutParams.MATCH_PARENT));
                } else {
                    //如果有一方为0,另一方不为0,为0点一行按0.1来处理进度条

                    if (lw < 0.2 && lw > 0) {
                        lw = 0.2f;
                        rw = 0.8f;
                    }

                    if (rw < 0.2 && rw > 0) {
                        rw = 0.2f;
                        lw = 0.8f;
                    }

                    if (lw == 1 && rw == 0) {
                        lw = 0.93f;
                        rw = 0.07f;
                    }

                    if (rw == 1 && lw == 0) {
                        rw = 0.93f;
                        lw = 0.07f;
                    }

                    tvLeft.setLayoutParams(new LinearLayout.LayoutParams((int) (tw * lw), LayoutParams.MATCH_PARENT));
                    tvRight.setLayoutParams(new LinearLayout.LayoutParams((int) (tw * rw), LayoutParams.MATCH_PARENT));
                }
            }
        });
        homeProgressValue.setText(LinkPkHelper.getPkSc(sc)); //截断,没有四舍五入
        guestProgressValue.setText(LinkPkHelper.getPkSc(sc1));
        //重新计算偏移量
        ivFlashLeft.clearAnimation();
        ivFlashRight.clearAnimation();
        showFlash(hasLeft,hasRight);
    }

    /**
     * @param isLeft true:左边胜利
     *               false:右边胜利
     */
    public void showResult(boolean isLeft) {
        if (isLeft) {
            tvRight.setBackgroundResource(R.drawable.bg_gradient_up_r_gray);
        } else {
            tvLeft.setBackgroundResource(R.drawable.bg_gradient_up_l_gray);
        }

    }

    /**
     * 流光效果展示
     */
    public void showFlash(boolean hasLeft, boolean hasRight) {
        this.hasLeft=hasLeft;
        this.hasRight=hasRight;
        if (hasLeft) {
            ivFlashLeft.setVisibility(VISIBLE);
            li.postDelayed(new Runnable() {
                @Override
                public void run() {
                    int mViewWidth = tvLeft.getWidth();
                    int mFlashWidth = ivFlashLeft.getWidth();
                    MasterLog.d("mFlashWidth", "mFlashWidth:" + mFlashWidth + "mViewWidth:" + mViewWidth);
                    //闪光组合动画
                    AnimationSet set = new AnimationSet(true);
                    AlphaAnimation alpha = new AlphaAnimation(1, 0.6f);
                    alpha.setRepeatCount(Animation.INFINITE);
                    TranslateAnimation translate = new TranslateAnimation(0, mViewWidth - mFlashWidth-10, 0, 0);
                    translate.setRepeatCount(Animation.INFINITE);

                    set.addAnimation(alpha);
                    set.addAnimation(translate);
                    set.setDuration(3000);
                    set.setInterpolator(new LinearInterpolator());
                    ivFlashLeft.startAnimation(set);
                }
            }, 50);

        }

        if (hasRight) {
            ivFlashRight.setVisibility(VISIBLE);
            li.post(new Runnable() {
                @Override
                public void run() {
                    int mViewWidth = tvRight.getWidth();
                    int mFlashWidth = ivFlashRight.getMeasuredWidth();
                    MasterLog.d("mFlashWidth", mViewWidth + "");
                    //闪光组合动画
                    AnimationSet set = new AnimationSet(true);
                    AlphaAnimation alpha = new AlphaAnimation(1, 0.6f);
                    alpha.setRepeatCount(Animation.INFINITE);
                    TranslateAnimation translate = new TranslateAnimation(0, -mViewWidth +mFlashWidth+10, 0, 0);
                    translate.setRepeatCount(Animation.INFINITE);

                    set.addAnimation(alpha);
                    set.addAnimation(translate);
                    set.setDuration(3000);
                    set.setInterpolator(new LinearInterpolator());
                    ivFlashRight.startAnimation(set);
                }
            });

        }

    }

    /**
     * 停止流光效果
     */
    public void stopFlash() {
        hasRight=false;
        hasLeft=false;
        ivFlashLeft.setVisibility(GONE);
        ivFlashLeft.clearAnimation();
        ivFlashRight.setVisibility(GONE);
        ivFlashRight.clearAnimation();
    }
}

2.单个view所形成的控件

 

package com.example.myapplication;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.Gravity;

/**
 * 文字旋转
 */
public class LeanTextView extends androidx.appcompat.widget.AppCompatTextView {
    public int getmDegrees() {
        return mDegrees;
    }

    public void setmDegrees(int mDegrees) {
        this.mDegrees = mDegrees;
        invalidate();
    }

    private int mDegrees;//倾斜度

    public LeanTextView(Context context) {
        super(context, null);
    }

    public LeanTextView(Context context, AttributeSet attrs) {
        super(context, attrs, android.R.attr.textViewStyle);
        this.setGravity(Gravity.CENTER);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LeanTextView);
        mDegrees = a.getDimensionPixelSize(R.styleable.LeanTextView_degree, 0);
        a.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());
        canvas.rotate(mDegrees, this.getWidth() / 2f, this.getHeight() / 2f);
        super.onDraw(canvas);
        canvas.restore();
    }
}

3.集成ViewGroup自定义的组合控件

package com.douyu.module.energy.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.douyu.module.energy.R;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 云标签
 */
public class TagsView extends ViewGroup {

    public interface Adapter {

        View getView(TagsView tagsView, int pos);

        int getCount();

        void onShowCross(int pos, View tagChildView, boolean isShow);
    }

  

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

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

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

    public void setOnTagListener(OnTagClickListener tagListener) {
        this.tagListener = tagListener;
    }

    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
      //初始化...
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //测量...
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
      //布局...
    }

    
    //其他若干实现方法..

  
}

4.复杂自定义控件

列表滑动,屏幕拖动,特效炫技,结合到算法的动态view

上面是通过代码层面来定义自定义控件的,通过产品和UI形态来定义的话,简单点说,就是静态与动态

特别炫的动效,不建议个人绘制,直接让UI出个svga,gift性能加载不好,也不建议,当然项目不大的情况下,无关乎性能的话,就随意。

自定义控件基础方法与类

方法
1.构造方法实现
做过自定义的朋友应该都知道的,自定义控件必须实现3个构造方法,那么为什么要实现它们呢?

2.onMeasure

  3.onLayout

  4.onDraw

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值