View第一部分自定义View 简单介绍及使用
Posted xzj_2013
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了View第一部分自定义View 简单介绍及使用相关的知识,希望对你有一定的参考价值。
自定义View的分类和使用场景分析
1.继承View/SurfaceView重写onDraw方法
这种方法主要用于实现一些不规则的效果,即这种效果不方便通过布局的组合方式来达到,往往需要静态或者动态的显示一些不规则的图形。很显然
这需要通过绘制的方式来实现,即重写onDraw方法。采用这种方式需要自己支持wrap_content,并且padding也需要自己处理。
2.继承ViewGroup派生特殊的Layout
这种方法主要用于实现自定义的布局,即除了LinearLayout,RelativeLayout,FrameLayout这几种系统的布局之外,我们需要重新定义一种新布局,
当某种效果看起来很像几种View组合在一起的时候,可以采用这种方式实现。采用这种方式稍微复杂一些,需要合适的处理ViewGroup的
测量布局这两个过程,并同时处理子元素的测量和布局过程。
3.继承特定的View(如TextView,ImageView等)
这种方法比较常见,一般用于扩展某种已有的View的功能,比如TextView,这种方法的实现比较简单,不需要自己支持wrap_content和padding等。
4.继承特定的ViewGroup(如LinearLayout,FrameLayout)
这种方法也比较常见,当某种效果看起来很像几种View组合起来的时候可以采用这种方法来实现,采用这种方法不需要自己处理ViewGroup的
测量和布局这两个过程。
需要注意这种方法和方法2的区别,一般来说方法2能实现的效果方法4也能实现,两者的主要区别在于方法2更加接近View的底层。
以上就是自定义View的四种方法,自定义View讲究的是灵活性,一种效果可能多种方式可以实现,我们需要做的是找到一种代价小最高效的方法去实现。
自定义View过程中需要注意的问题
要准确的实现自定义View,我们需要处理一些为题,这些问题可能会影响Viwq的正常使用,有些可能会导致内存泄露等问题。
1.让View支持wrap_content
继承的View或者ViewGroup如果不在onMeasure对wrap_content进行特殊处理,那么当外界使用wrap_content时,会无法达到预期的效果
2.如果有必要,让你的View支持padding
继承View的控件,如果不在onDraw中处理padding,那么padding属性将无法起作用,同时继承ViewGroup的控件也需要在
onMeasure和onLayout中考虑padding和magin对其效果的影响
3.尽量不要在View中使用Handler,没必要
View内部本身已经提供了Post系列的办法,完全可以替代handler的作用,除非你很明确需要使用Handler来发送消息
4.View中如果有线程或者动画,需要及时停止,参考View#onDetachedFromWindow
如果有线程或者动画需要停止,那么onDetachedFromWindow是一个很好的时机,当包含此View的Activity退出或者当前View被remove时,View的
onDetachedFromWindow方法会被调用,和此方法对应的是onAttachedToWindow,当包含此View的Activity启动是View的onAttachedToWindow方法将会调用。
同时当View不可见时我们也需要停止线程和动画,如果不及时处理这种问题,很有可能会造成内存泄露。
5.View带有滑动嵌套情形时,需要处理好滑动冲突
自定义View示例
1.继承View
首先建立一个属性文件,声明了一个自定义属性集合,在这个集合中你可以添加许多自己需要的属性,其格式类型是name = 属性名 format = 属性值的类型
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name = "circleview">
<attr name = "circle_color" format = "color"/>
</declare-styleable>
</resources>
然后是在View的构造方法中解析自定义的属性值并做处理
public CircleView(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
//加载自定义属性集合circleview
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.circleview);
//从集合中获取设置的属性值
mColor = a.getColor(R.styleable.circleview_circle_color, Color.RED);
//解析完毕释放资源
a.recycle();
init();
最后在布局文件中使用自定义属性
需要注意的是一定要通过命名空间去使用自定义属性,即一定要先声明才能使用该属性
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:mview="http://schemas.android.com/apk/res/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.example.myroundviewactivity.CircleView
android:id="@+id/m_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
mview:circle_color = "#ffffff"
/>
</RelativeLayout>
一个简单的自定义View代码示例:
package com.example.myroundviewactivity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class CircleView extends View
private int mColor = Color.RED;
//抗锯齿
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public CircleView(Context context)
super(context);
// TODO Auto-generated constructor stub
init();
public CircleView(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
//自定义属性
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.circleview);
mColor = a.getColor(R.styleable.circleview_circle_color, Color.RED);
a.recycle();
init();
public CircleView(Context context, AttributeSet attrs)
this(context,attrs,0);
private void init()
mPaint.setColor(mColor);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//给View添加wrap_content支持
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST)
setMeasuredDimension(200, 200);
else if(widthSpecMode == MeasureSpec.AT_MOST)
setMeasuredDimension(200, heightSpecSize);
else if(heightSpecMode == MeasureSpec.AT_MOST)
setMeasuredDimension(widthSpecSize, 200);
@Override
protected void onDraw(Canvas canvas)
// TODO Auto-generated method stub
super.onDraw(canvas);
//使自定义View支持padding属性
final int paddingleft = getPaddingLeft();
final int paddingright = getPaddingRight();
final int paddingtop = getPaddingTop();
final int paddingbottom = getPaddingBottom();
int width = getWidth()-paddingleft-paddingright;
int height = getHeight()-paddingtop-paddingbottom;
int radius = Math.max(width, height)/2;
canvas.drawCircle(paddingleft+width/2, paddingtop+height/2, radius, mPaint);
2.继承ViewGroup派生特殊的Layout
http://blog.csdn.net/lmj623565791/article/details/38339817/
3.继承特定的View
package com.example.commonview;
import android.content.Context;
import android.util.AttributeSet;
/**
* 一直处于滚动状态的textview
*/
public class AlwaysMarqueeText extends TextView
public AlwaysMarqueeText(Context context)
super(context);
public AlwaysMarqueeText(Context context, AttributeSet attrs)
super(context, attrs);
public AlwaysMarqueeText(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
@Override
public boolean isFocused()
return true;
4.继承特定的ViewGroup
package com.example.commonview;
import java.util.Date;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
@SuppressLint("NewApi")
public class TimeAndDateView extends LinearLayout
private View rootView;
private TextView tvDate;
private TextView tvTime;
private String currentTime;
private String currentDate;
private String currentWeek;
private final static int UPDATE_TIME = 10001;
private Handler mHandler = new Handler()
@Override
public void handleMessage(android.os.Message msg)
switch (msg.what)
case UPDATE_TIME:
updateDateTime();
mHandler.sendEmptyMessageDelayed(UPDATE_TIME, 10 * 1000);
break;
;
;
public TimeAndDateView(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
rootView = LayoutInflater.from(context).inflate(R.layout.time_date_layout, this, true);
tvDate = (TextView)rootView.findViewById(R.id.date_textview);
tvTime = (TextView)rootView.findViewById(R.id.time_textview);
currentTime = "HH:mm";
currentDate = "MM/dd";
currentWeek = "EEEE";
public TimeAndDateView(Context context, AttributeSet attrs)
super(context, attrs);
rootView = LayoutInflater.from(context).inflate(R.layout.time_date_layout, this, true);
tvDate = (TextView)rootView.findViewById(R.id.date_textview);
tvTime = (TextView)rootView.findViewById(R.id.time_textview);
currentTime = "HH:mm";
currentDate = "MM/dd";
currentWeek = "EEEE";
public TimeAndDateView(Context context)
super(context);
rootView = LayoutInflater.from(context).inflate(R.layout.time_date_layout, this, true);
tvDate = (TextView)rootView.findViewById(R.id.date_textview);
tvTime = (TextView)rootView.findViewById(R.id.time_textview);
currentTime = "HH:mm";
currentDate = "MM/dd";
currentWeek = "EEEE";
public void start()
if (mHandler.hasMessages(UPDATE_TIME))
mHandler.removeMessages(UPDATE_TIME);
mHandler.sendEmptyMessage(UPDATE_TIME);
public void stop()
mHandler.removeMessages(UPDATE_TIME);
private void updateDateTime()
Date date = SynchServerTimer.getDate();
tvTime.setText(SmartLunznDate.getChinaDateStr(currentTime, date));
tvDate.setText(SmartLunznDate.getChinaDateStr(currentDate, date) + " "
+ SmartLunznDate.getChinaDateStr(currentWeek, date));
以上是关于View第一部分自定义View 简单介绍及使用的主要内容,如果未能解决你的问题,请参考以下文章