您的位置:首页 > 其它

一步一步走向自定义控件

2017-04-01 10:08 141 查看
上个月搭配了自己的开发环境。

有了自己的环境=有了环境想搞事情。

然后这个月就想搞搞事情了。

自定义控件确实很强大,看到灵机上的OppositeLayout不禁深深钦佩。

其实一直想自定义控件,但是到底怎么自定义的呢,需要怎么样去学呢?我也不怎么晓得。

我比较笨–>我的想法是一步一步慢慢探索,摸着石头过河。–>会用别人定义的–>看懂别人的代码–>模仿着来写–>写自己的

大神博客

自定义dialog
BaseDialog

ChildrenDialog
关键代码

Animation
核心代码

Dialog

自定义TextView

自定义Button
StateButton

神一样的控件自定义FrameLayout

自定义View

总结

自定义dialog

这个自定义dialog的灵感来自于加载动画–>

正常来说我们可以先写一个BaseDialog

BaseDialog

/**
* <b>Project:</b> ${file_name}<br>
* <b>Create Date:</b> 2017/3/18<br>
* <b>Author:</b> Tongson<br>
* <b>Description:</b> Tongson's Dialog的爸爸 <br>
*/

public abstract class TongsonBaseDialog extends Dialog {

private Context mContext;

public TongsonBaseDialog(Context context) {
super(context, R.style.TongsonBaseDialogStyle);
mContext = context;
initEnterExitAnim();
}

public TongsonBaseDialog(Context context, int theme) {
super(context, theme);
mContext = context;
initEnterExitAnim();
}

/**
* 进场动画
*/
public void initEnterExitAnim() {
Window dialogWindow = getWindow();
dialogWindow.setGravity(Gravity.CENTER); // 此处可以设置dialog显示的位置为居中
dialogWindow.setWindowAnimations(R.style.dialogWindowAnim);// 添加动画效果
int widthPixels;
int heightPixels;
WindowManager.LayoutParams layoutParams = dialogWindow.getAttributes();
DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
widthPixels = dm.widthPixels;
heightPixels = dm.heightPixels;
layoutParams.height = heightPixels;
layoutParams.width = widthPixels;
dialogWindow.setAttributes(layoutParams);
}
}


BaseDialog:身为一个dialog的爸爸应该怎么去写?我的话开始的时候写得不多,感觉不需要写太多–>先写孩纸,然后把孩纸的共同点交给爸爸。爸爸是有很多共同点的存在,而孩纸是青出于蓝而胜于蓝的存在。

R.style.dialogWindowAnim:这个就是动画效果。先讲完dialog的,动画等等再说。

ChildrenDialog

然后我们来看看这个孩纸的dialog怎么去写呢?

在项目里,我们有各种各样的dialog

而且根据需求会写各种各样的dialog,那我们就写呗

列举一下项目中我们都有用到的dialog

LoadingDialog

GetPhotoDialog

TipsDialog

PayDialog

PermissionDialog

ExitDialog

DownloadDialog

等等

关键代码

setContentView(R.layout.dialog_layout);


然后自己想干嘛干嘛。哈。哈。

Animation

感觉是很重要的,Dialog飞来飞去的炫酷感会使用户飞。

怎么加入自己想要的动画呢?

这个开始我也不大会,然后就找别人的代码啊。

https://github.com/gepriniusce/NiftyDialogEffects

https://github.com/gepriniusce/NiftyNotification

核心代码

this.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialogInterface) {

mLinearLayoutView.setVisibility(View.VISIBLE);
if (type == null) {
type = Effectstype.Slidetop;
}
start(type);

}
});


private void start(Effectstype type) {
BaseEffects animator = type.getAnimator();
if (mDuration != -1) {
animator.setDuration(Math.abs(mDuration));
}
animator.start(mRelativeLayoutView);
}


其实原理很简单,dialog有一个OnShowListener,然后再start动画!

Dialog

其实自定义Dialog的话,还是要多看看Dialog这个类的代码,我们重写一下方法就行了是不是好简单!?

自定义TextView

对于自定义的TextView感觉比较有用的是setTypeface(加载自己的字体库)

直接看代码吧–>

/**
* <b>Project:</b> ${file_name}<br>
* <b>Create Date:</b> 2017/4/4<br>
* <b>Author:</b> Tongson<br>
* <b>Description:</b>  自定义字体库TextView <br>
*/
public class TongsonTextView extends TextView {

public static Typeface myTypeface;

public TongsonTextView(Context context) {
super(context);
setTTFstyle();
}

public TongsonTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setTTFstyle();
}

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

private void setTTFstyle() {
Typeface typeface= getTtf();
if (null != typeface) {
setTypeface(typeface);
}
}

/**
* 加载字体库
* <p>
* 此处应该在Application中
*
* @param context
*/
public static void loadTtf(Context context) {
Typeface fontFace = null;
try {
fontFace = Typeface.createFromAsset(context.getAssets(), "fonts/msyhl.ttc");
} catch (RuntimeException e) {
e.printStackTrace();
}
if (fontFace != null) {
myTypeface = fontFace;
}
}

/**
* 获取字体
*
* @return
*/
private Typeface getTtf() {
return myTypeface;
}
}


核心代码

setTypeface(typeface);


自定义Button

Button的话个人比较喜欢StateButton

https://github.com/niniloveyou/StateButton

先看懂大神代码吧–>

values中的attrs –>自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
</declare-styleable>
<declare-styleable name="StateButton">
<attr name="xxx" format="xxx|reference"/>
</declare-styleable>
</resources>


获取attrs属性

利用这些属性与GradientDrawable对控件的属性做设置

真的写得不错的代码,觉得很值得我学习

StateButton

public class StateButton extends AppCompatButton {

//text color
private int mNormalTextColor = 0;
private int mPressedTextColor = 0;
private int mUnableTextColor = 0;
ColorStateList mTextColorStateList;

//animation duration
private int mDuration = 0;

//radius
private float mRadius = 0;
private boolean mRound;

//stroke
private float mStrokeDashWidth = 0;
private float mStrokeDashGap = 0;
private int mNormalStrokeWidth = 0;
private int mPressedStrokeWidth = 0;
private int mUnableStrokeWidth = 0;
private int mNormalStrokeColor = 0;
private int mPressedStrokeColor = 0;
private int mUnableStrokeColor = 0;

//background color
private int mNormalBackgroundColor = 0;
private int mPressedBackgroundColor = 0;
private int mUnableBackgroundColor = 0;

private GradientDrawable mNormalBackground;
private GradientDrawable mPressedBackground;
private GradientDrawable mUnableBackground;

private int[][] states;

StateListDrawable mStateBackground;

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

public StateButton(Context context, AttributeSet attrs) {
this(context, attrs, android.support.v7.appcompat.R.attr.buttonStyle);
}

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

private void setup(AttributeSet attrs) {

states = new int[4][];

Drawable drawable = getBackground();
if(drawable != null && drawable instanceof StateListDrawable){
mStateBackground = (StateListDrawable) drawable;
}else{
mStateBackground = new StateListDrawable();
}

mNormalBackground = new GradientDrawable();
mPressedBackground = new GradientDrawable();
mUnableBackground = new GradientDrawable();

//pressed, focused, normal, unable
states[0] = new int[] { android.R.attr.state_enabled, android.R.attr.state_pressed };
states[1] = new int[] { android.R.attr.state_enabled, android.R.attr.state_focused };
states[3] = new int[] { -android.R.attr.state_enabled};
states[2] = new int[] { android.R.attr.state_enabled };

TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.StateButton);

//get original text color as default
//set text color
mTextColorStateList = getTextColors();
int mDefaultNormalTextColor = mTextColorStateList.getColorForState(states[2], getCurrentTextColor());
int mDefaultPressedTextColor = mTextColorStateList.getColorForState(states[0], getCurrentTextColor());
int mDefaultUnableTextColor = mTextColorStateList.getColorForState(states[3], getCurrentTextColor());
mNormalTextColor = a.getColor(R.styleable.StateButton_normalTextColor, mDefaultNormalTextColor);
mPressedTextColor = a.getColor(R.styleable.StateButton_pressedTextColor, mDefaultPressedTextColor);
mUnableTextColor = a.getColor(R.styleable.StateButton_unableTextColor, mDefaultUnableTextColor);
setTextColor();

//set animation duration
mDuration = a.getInteger(R.styleable.StateButton_animationDuration, mDuration);
mStateBackground.setEnterFadeDuration(mDuration);
mStateBackground.setExitFadeDuration(mDuration);

//set background color
mNormalBackgroundColor = a.getColor(R.styleable.StateButton_normalBackgroundColor, 0);
mPressedBackgroundColor = a.getColor(R.styleable.StateButton_pressedBackgroundColor, 0);
mUnableBackgroundColor = a.getColor(R.styleable.StateButton_unableBackgroundColor, 0);
mNormalBackground.setColor(mNormalBackgroundColor);
mPressedBackground.setColor(mPressedBackgroundColor);
mUnableBackground.setColor(mUnableBackgroundColor);

//set radius
mRadius = a.getDimensionPixelSize(R.styleable.StateButton_radius, 0);
mRound = a.getBoolean(R.styleable.StateButton_round, false);
mNormalBackground.setCornerRadius(mRadius);
mPressedBackground.setCornerRadius(mRadius);
mUnableBackground.setCornerRadius(mRadius);

//set stroke
mStrokeDashWidth = a.getDimensionPixelSize(R.styleable.StateButton_strokeDashWidth, 0);
mStrokeDashGap = a.getDimensionPixelSize(R.styleable.StateButton_strokeDashWidth, 0);
mNormalStrokeWidth = a.getDimensionPixelSize(R.styleable.StateButton_normalStrokeWidth, 0);
mPressedStrokeWidth = a.getDimensionPixelSize(R.styleable.StateButton_pressedStrokeWidth, 0);
mUnableStrokeWidth = a.getDimensionPixelSize(R.styleable.StateButton_unableStrokeWidth, 0);
mNormalStrokeColor = a.getColor(R.styleable.StateButton_normalStrokeColor, 0);
mPressedStrokeColor = a.getColor(R.styleable.StateButton_pressedStrokeColor, 0);
mUnableStrokeColor = a.getColor(R.styleable.StateButton_unableStrokeColor, 0);
setStroke();

//set background
mStateBackground.addState(states[0], mPressedBackground);
mStateBackground.addState(states[1], mPressedBackground);
mStateBackground.addState(states[3], mUnableBackground);
mStateBackground.addState(states[2], mNormalBackground);
setBackgroundDrawable(mStateBackground);
a.recycle();
}

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

/****************** stroke color *********************/

public void setNormalStrokeColor(@ColorInt int normalStrokeColor) {
this.mNormalStrokeColor = normalStrokeColor;
setStroke(mNormalBackground, mNormalStrokeColor, mNormalStrokeWidth);
}

public void setPressedStrokeColor(@ColorInt int pressedStrokeColor) {
this.mPressedStrokeColor = pressedStrokeColor;
setStroke(mPressedBackground, mPressedStrokeColor, mPressedStrokeWidth);
}

public void setUnableStrokeColor(@ColorInt int unableStrokeColor) {
this.mUnableStrokeColor = unableStrokeColor;
setStroke(mUnableBackground, mUnableStrokeColor, mUnableStrokeWidth);
}

public void setStateStrokeColor(@ColorInt int normal, @ColorInt int pressed, @ColorInt int unable){
mNormalStrokeColor = normal;
mPressedStrokeColor = pressed;
mUnableStrokeColor = unable;
setStroke();
}

/****************** stroke width *********************/

public void setNormalStrokeWidth(int normalStrokeWidth) {
this.mNormalStrokeWidth = normalStrokeWidth;
setStroke(mNormalBackground, mNormalStrokeColor, mNormalStrokeWidth);
}

public void setPressedStrokeWidth(int pressedStrokeWidth) {
this.mPressedStrokeWidth = pressedStrokeWidth;
setStroke(mPressedBackground, mPressedStrokeColor, mPressedStrokeWidth);
}

public void setUnableStrokeWidth(int unableStrokeWidth) {
this.mUnableStrokeWidth = unableStrokeWidth;
setStroke(mUnableBackground, mUnableStrokeColor, mUnableStrokeWidth);
}

public void setStateStrokeWidth(int normal, int pressed, int unable){
mNormalStrokeWidth = normal;
mPressedStrokeWidth = pressed;
mUnableStrokeWidth= unable;
setStroke();
}

public void setStrokeDash(float strokeDashWidth, float strokeDashGap) {
this.mStrokeDashWidth = strokeDashWidth;
this.mStrokeDashGap = strokeDashWidth;
setStroke();
}

private void setStroke(){
setStroke(mNormalBackground, mNormalStrokeColor, mNormalStrokeWidth);
setStroke(mPressedBackground, mPressedStrokeColor, mPressedStrokeWidth);
setStroke(mUnableBackground, mUnableStrokeColor, mUnableStrokeWidth);
}

private void setStroke(GradientDrawable mBackground, int mStrokeColor, int mStrokeWidth) {
mBackground.setStroke(mStrokeWidth, mStrokeColor, mStrokeDashWidth, mStrokeDashGap);
}

/********************   radius  *******************************/

public void setRadius(@FloatRange(from = 0) float radius) {
this.mRadius = radius;
mNormalBackground.setCornerRadius(mRadius);
mPressedBackground.setCornerRadius(mRadius);
mUnableBackground.setCornerRadius(mRadius);
}

public void setRound(boolean round){
this.mRound = round;
int height = getMeasuredHeight();
if(mRound){
setRadius(height / 2f);
}
}

public void setRadius(float[] radii){
mNormalBackground.setCornerRadii(radii);
mPressedBackground.setCornerRadii(radii);
mUnableBackground.setCornerRadii(radii);
}

/********************  background color  **********************/

public void setStateBackgroundColor(@ColorInt int normal, @ColorInt int pressed, @ColorInt int unable){
mPressedBackgroundColor = normal;
mNormalBackgroundColor = pressed;
mUnableBackgroundColor = unable;
mNormalBackground.setColor(mNormalBackgroundColor);
mPressedBackground.setColor(mPressedBackgroundColor);
mUnableBackground.setColor(mUnableBackgroundColor);
}

public void setNormalBackgroundColor(@ColorInt int normalBackgroundColor) {
this.mNormalBackgroundColor = normalBackgroundColor;
mNormalBackground.setColor(mNormalBackgroundColor);
}

public void setPressedBackgroundColor(@ColorInt int pressedBackgroundColor) {
this.mPressedBackgroundColor = pressedBackgroundColor;
mPressedBackground.setColor(mPressedBackgroundColor);
}

public void setUnableBackgroundColor(@ColorInt int unableBackgroundColor) {
this.mUnableBackgroundColor = unableBackgroundColor;
mUnableBackground.setColor(mUnableBackgroundColor);
}

/*******************alpha animation duration********************/
public void setAnimationDuration(@IntRange(from = 0)int duration){
this.mDuration = duration;
mStateBackground.setEnterFadeDuration(mDuration);
}

/***************  text color   ***********************/

private void setTextColor() {
int[] colors = new int[] {mPressedTextColor, mPressedTextColor, mNormalTextColor, mUnableTextColor};
mTextColorStateList = new ColorStateList(states, colors);
setTextColor(mTextColorStateList);
}

public void setStateTextColor(@ColorInt int normal, @ColorInt int pressed, @ColorInt int unable){
this.mNormalTextColor = normal;
this.mPressedTextColor = pressed;
this.mUnableTextColor = unable;
setTextColor();
}

public void setNormalTextColor(@ColorInt int normalTextColor) {
this.mNormalTextColor = normalTextColor;
setTextColor();

}

public void setPressedTextColor(@ColorInt int pressedTextColor) {
this.mPressedTextColor = pressedTextColor;
setTextColor();
}

public void setUnableTextColor(@ColorInt int unableTextColor) {
this.mUnableTextColor = unableTextColor;
setTextColor();
}
}


神一样的控件自定义FrameLayout

这个就是公司的OppositeLayout

好强大,也是看懂代码先,然后一步一步学习,代码看多了,敲多了就会自己写了嘛。

代码不晓得贴不贴不出来好[捂脸]。

以上的算是自定义控件的一个入门吧。

自定义View

回过头来,我们可以再看看大神的博客

大神博客

更详细的入门教程。

总结

如果想真正弄明白怎样自定义View,绘制各种View,还是要先把基础搞好,参考优秀代码,多敲大神demo,学着写,自己写。

先睡觉,以后再补充
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  控件