android的自定义控件
来源:互联网 发布:三端口环形器原理 编辑:程序博客网 时间:2024/05/21 18:33
1.toast
- Toast toast = Toast.makeText(this, "自定义的toast", Toast.LENGTH_SHORT);
- toast.setGravity(Gravity.TOP, 30, 30);
- View view = LayoutInflater.from(this).inflate(R.layout.toast, null);
- toast.setView(view);
- toast.show();
2.Notification
- mNotify = new Notification(R.drawable.icon, "通知", System.currentTimeMillis());
- // 正在运行,不允许被清除
- mNotify.flags = Notification.FLAG_ONGOING_EVENT;
- //震动
- mNotify.defaults |= Notification.DEFAULT_VIBRATE;
- long[] vibrates = new long[]{0, 100, 200, 300};
- mNotify.vibrate = vibrates ;
声明震动权限<uses-permission android:name="android.permission.VIBRATE"></uses-permission> 注意模拟器没有震动功能,需要真机测试
- // 定制intent
- Intent intent = new Intent(this, MyService.class);
- PendingIntent pendingIntent = PendingIntent.getService(this, 1, intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
- mNotify.contentIntent = pendingIntent;
- // 自定义通知布局
- RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.updatenotify);
- mNotify.contentView = contentView;
- // 使用通知
- mNotifyMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- mNotifyMgr.notify(R.string.hello, mNotify);
- //更新通知
- mNotify.contentView.setProgressBar(R.id.progressBar1, NOTITY_PROGRESS_MAX, progress, false);
- mNotifyMgr.notify(R.string.hello, mNotify);
- if (progress == NOTITY_PROGRESS_MAX) {
- Toast.makeText(this, "下载完成,请查看通知安装", Toast.LENGTH_SHORT).show();
- }
3.dialog
- protected Dialog onCreateDialog(int id) {
- Dialog dialog = new Dialog(this);
- dialog.setContentView(R.layout.dialog);
- dialog.setTitle("标题");
- return dialog;
- }
- //在需要显示的地方写
- showDialog(1);
4.menu
自定义菜单,分析菜单的特征
什么条件下显示: 按Menu
什么条件下关闭:
1) 当菜单显示时,再点击一次菜单按钮
2) 某一个菜单项被点击
3) back Activity不响应back
4) 其它Activity激活
5) 点击菜单和状态栏以外的区域
补充:当菜单存在时,点击菜单以外区域,界面不能响应用户操作
- public class MainActivity extends Activity implements OnClickListener {
- private PopupWindow mOptionsMenu;
- private int[] menuItemIDs = new int[] { R.id.menuitem1, R.id.menuitem2, R.id.menuitem3,
- R.id.menuitem4, R.id.menuitem5, R.id.menuitem6, R.id.menuitem7, R.id.menuitem8,
- R.id.empty };
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- View contentView = LayoutInflater.from(this).inflate(R.layout.optionsmenu, null);
- mOptionsMenu = new PopupWindow(contentView, LayoutParams.FILL_PARENT,
- LayoutParams.WRAP_CONTENT);
- initMenuItem(contentView);
- }
- @Override
- protected void onPause() {
- super.onPause();
- closeMenuIfExist();
- }
- private boolean closeMenuIfExist() {
- if (mOptionsMenu.isShowing()) {
- mOptionsMenu.dismiss();
- return true;
- }
- return false;
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (closeMenuIfExist()) {
- return true;
- }
- }
- return super.onKeyDown(keyCode, event);
- }
- private void initMenuItem(View contentView) {
- for (int i = 0; i < menuItemIDs.length; i++) {
- contentView.findViewById(menuItemIDs[i]).setOnClickListener(this);
- }
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- if (!closeMenuIfExist()) {
- mOptionsMenu.showAtLocation(findViewById(R.id.main), Gravity.BOTTOM, 0, 0);
- }
- return false;
- }
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.menuitem1:
- Intent intent = new Intent();
- intent.setClass(this, Second.class);
- startActivity(intent);
- break;
- case R.id.menuitem2:
- break;
- case R.id.menuitem3:
- break;
- case R.id.menuitem4:
- break;
- case R.id.menuitem5:
- break;
- case R.id.menuitem6:
- break;
- case R.id.menuitem7:
- break;
- case R.id.menuitem8:
- break;
- case R.id.empty:
- break;
- default:
- break;
- }
- mOptionsMenu.dismiss();
- }
- }
注意,R.id.empty指的是菜单外面的view,可以用帧布局放置
可以用selector 为菜单设置点击效果
菜单项显示图片和文本
两类:
1) 图片和文本做成一张图片
2) GridView
布局嵌套
5.progress
- <SeekBar
- android:id="@+id/progress"
- style="?android:attr/progressBarStyleHorizontal"
- android:progressDrawable="@drawable/seek_background"
- android:thumb="@drawable/thumb"
- android:layout_width="346dip"
- android:layout_height="32dip"
- android:maxHeight="10dip"
- android:paddingLeft="8dip"
- android:paddingRight="8dip"
- android:paddingTop="2dip"
- android:paddingBottom="6dip"
- android:max="1000"/>
- <!-- android:minHeight="10dip"-->
- seek_background.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <layer-list
- xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@android:id/background" android:drawable="@drawable/time_line_bg" />
- <item android:id="@android:id/progress" android:drawable="@drawable/progress_time" />
- </layer-list>
tumb.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <selector
- xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- 按下状态 -->
- <item
- android:state_pressed="true"
- android:drawable="@drawable/drag_btn_down" />
- <!-- 普通无焦点状态 -->
- <item
- android:state_focused="false"
- android:state_pressed="false"
- android:drawable="@drawable/drag_btn" />
- </selector>
6.view
- public class LabelView extends View {
- private Paint mTextPaint;
- private String mText;
- private int mAscent;
- /**
- * 定义一个构造器来初始化这个自定义的view,这个构造器可以在java代码中用来生成view 如 new LabelView(context)
- *
- * @param context
- * 上下文
- */
- public LabelView(Context context) {
- super(context);
- initLabelView();
- }
- /**
- * @param context
- * 上下文
- * @param attrs
- * 从带styleable的xml中读到的属性
- */
- public LabelView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initLabelView();
- // 从R.styleable.LabelView文件中获得属性集合
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LabelView);
- // 通过typedArray.getString或者typedArray.getInt获得对应的属性设定的值
- // 属性的名称为styleable名称“LabelView”,加上“_”,再加上属性名称"text",组成“LabelView_text”
- CharSequence s = a.getString(R.styleable.LabelView_text);
- if (s != null) {
- // 设置text的content
- setText(s.toString());
- }
- // 设置text的color,如果没有设置,默认值为0xFF000000
- setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xFF000000));
- // 设置text的文字大小
- int textSize = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0);
- if (textSize > 0) {
- setTextSize(textSize);
- }
- // 之前设置的属性,设置循环利用
- a.recycle();
- }
- /**
- * 新建画笔和设置画笔的样式
- */
- private final void initLabelView() {
- mTextPaint = new Paint();
- mTextPaint.setAntiAlias(true);
- mTextPaint.setTextSize(16);
- mTextPaint.setColor(0xFF000000);
- setPadding(3, 3, 3, 3);
- }
- /**
- * 设置文字内容,可以类外使用new view后,再使用view.setText设置内容,在构造器处被调用
- * @param text
- */
- public void setText(String text) {
- mText = text;
- requestLayout();
- invalidate();
- }
- /**设置字体大小,在构造器处被调用
- * @param size
- */
- public void setTextSize(int size) {
- mTextPaint.setTextSize(size);
- requestLayout();
- invalidate();
- }
- /**设置字体颜色,在构造器处被调用
- * @param color
- */
- public void setTextColor(int color) {
- mTextPaint.setColor(color);
- invalidate();
- }
- /**设置自定义view的显示的大小
- * @see android.view.View#onMeasure(int, int)
- */
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- //measureWidth和measureHeight事自定义的两个用来设置宽度和高度的方法
- setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
- }
- /**
- * 设置宽度,写法一般都遵循这样的框架,需要getMode和getSize来分辨用户设置的“match_parent”还是“wrap_content”等
- * @param 具体的值
- * @return 返回宽度
- */
- private int measureWidth(int measureSpec) {
- int result = 0;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
- if (specMode == MeasureSpec.EXACTLY) {
- // 确切地知道大小,即设置width=“123”等这些具体数值
- result = specSize;
- } else {
- // 这里相当于设置宽度为wrapContent
- result = (int) mTextPaint.measureText(mText) + getPaddingLeft() + getPaddingRight();
- if (specMode == MeasureSpec.AT_MOST) {
- // 相当于设置成UNSPECIFIED
- result = Math.min(result, specSize);
- }
- }
- return result;
- }
- /**
- *与measureWidth方法类似
- */
- private int measureHeight(int measureSpec) {
- int result = 0;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
- mAscent = (int) mTextPaint.ascent();
- if (specMode == MeasureSpec.EXACTLY) {
- result = specSize;
- } else {
- result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop() + getPaddingBottom();
- if (specMode == MeasureSpec.AT_MOST) {
- result = Math.min(result, specSize);
- }
- }
- return result;
- }
- /**
- * 描述view的画法的一个方法,在invalidate时回调
- */
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint);
- }
- }
其中context.obtainStyledAttributes(attrs, R.styleable.LabelView);指的是从xml中获取属性集合
你可以新建一项位于values下的xml文件 resource下面包含以下代码
- <declare-styleable name="LabelView">
- <attr format="string" name="text" />
- <attr format="color" name="textColor" />
- <attr format="dimension" name="textSize" />
- </declare-styleable>
或者像这样写
- <?xml version="1.0" encoding="UTF-8"?>
- <resources>
- <declare-styleable name="EditTextExt">
- <attr name="Text" format="reference|string"></attr>
- <attr name="Oriental">
- <enum name="Horizontal" value="1"></enum>
- <enum name="Vertical" value="0"></enum>
- </attr>
- </declare-styleable>
- </resources>
分析measureWidth和measureHeight方法
依据specMode的值,(MeasureSpec有3种模式分别是UNSPECIFIED, EXACTLY和AT_MOST)如果是AT_MOST,specSize 代表的是最大可获得的空间;
如果是EXACTLY,specSize 代表的是精确的尺寸;
如果是UNSPECIFIED,对于控件尺寸来说,没有任何参考意义。
经过代码测试就知道,当我们设置width或height为fill_parent时,容器在布局时调用子 view的measure方法传入的模式是EXACTLY,因为子view会占据剩余容器的空间,所以它大小是确定的。
而当设置为 wrap_content时,容器传进去的是AT_MOST, 表示子view的大小最多是多少,这样子view会根据这个上限来设置自己的尺寸。当子view的大小设置为精确值时,容器传入的是EXACTLY, 而MeasureSpec的UNSPECIFIED模式目前还没有发现在什么情况下使用。
View的onMeasure方法默认行为是当模式为UNSPECIFIED时,设置尺寸为mMinWidth(通常为0)或者背景drawable的最小尺寸,当模式为EXACTLY或者AT_MOST时,尺寸设置为传入的MeasureSpec的大小。
有个观念需要纠正的是,fill_parent应该是子view会占据剩下容器的空间,而不会覆盖前面已布局好的其他view空间,当然后面布局子 view就没有空间给分配了,所以fill_parent属性对布局顺序很重要。以前所想的是把所有容器的空间都占满了,难怪google在2.2版本里把fill_parent的名字改为match_parent.
在两种情况下,你必须绝对的处理这些限制。在一些情况下,它可能会返回超出这些限制的尺寸,在这种情况下,你可以让父元素选择如何对待超出的View,使用裁剪还是滚动等技术。
最后,这个view就可以像平时我们在xml里面布局对待其他控件一样
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res/org.yuchen.customview"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/hello" />
- <org.yuchen.customview.LabelView
- android:background="@drawable/blue"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:text="Blue"
- app:textSize="20dp" />
- <org.yuchen.customview.LabelView
- android:background="@drawable/red"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:text="Red" />
- </LinearLayout>
注意需要有命名空间,所以你明白为什么我们每个xml布局都包含xmlns:android="http://schemas.android.com/apk/res/android"这句话了吧,因为用到android:layout_width等的引用
- xmlns:app="http://schemas.android.com/apk/res/org.yuchen.customview"
- 必须包含完整包名路径
- lt;org.yuchen.customview.LabelView
- app:text="Blue"
- app:textSize="20dp"
自定义view还可以有第二种写法
- package com.terry.attrs;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.widget.EditText;
- import android.widget.LinearLayout;
- import android.widget.TextView;
- public class EditTextExt1 extends LinearLayout {
- private String Text = "";
- public EditTextExt1(Context context) {
- this(context, null);
- // TODO Auto-generated constructor stub
- }
- public EditTextExt1(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- int resouceId = -1;
- TextView tv = new TextView(context);
- EditText et = new EditText(context);
- resouceId = attrs.getAttributeResourceValue(null, "Text", 0);
- if (resouceId > 0) {
- Text = context.getResources().getText(resouceId).toString();
- } else {
- Text = "";
- }
- tv.setText(Text);
- addView(tv);
- addView(et, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
- LayoutParams.WRAP_CONTENT));
- this.setGravity(LinearLayout.VERTICAL);
- }
- }
这种写法,简单明了,不需要额外XML的配置,就可以在我们的VIEW文件下使用。
以上代码通过构造函数中引入的AttributeSet 去查找XML布局的属性名称,然后找到它对应引用的资源ID去找值。使用也时分方便。所以一直以来我也是很喜欢这种写法。
如上,自定好VIEW文件就可以在XML布局下如此使用:
- <com.terry.attrs.EditTextExt1 android:id="@+id/ss3"
- android:layout_width="wrap_content" android:layout_height="wrap_content"
- Text="@string/app_name" ></com.terry.attrs.EditTextExt1>
部分代码参考自http://www.cnblogs.com/TerryBlog/archive/2010/11/03/1868431.html
转载自http://blog.csdn.net/iamkila/article/details/7294137
- android的自定义控件
- android的自定义控件
- Android.自定义控件的实现
- Android.自定义控件的实现
- android的一些自定义控件
- Android自定义控件的实现
- Android自定义控件的实现
- Android自定义控件的属性
- Android自定义控件的属性
- Android 自定义控件的使用
- Android.自定义控件的实现
- Android自定义控件的好处
- 收藏的Android自定义控件
- Android 自定义控件的属性
- Android的自定义控件起步
- Android自定义控件的学习心得
- Android 自定义控件的刷新
- Android 自定义控件的刷新
- 那天有个小孩教我WCF[一][1/3]
- controlfile 维护
- Java小应用程序
- dev c++缺失gnu make file
- android之AutoCompleteTextView
- android的自定义控件
- VMware上Clone Ubuntu虚拟机后找不到eth0
- flash 基于图像像素做碰撞检测
- enode框架step by step之框架要实现的目标的分析思路剖析1
- PHP实践之路(四)PHP中常量和变量
- Java计算器源码
- 上网网速慢怎么办?半分钟搞定
- Java中Properties类的使用
- 在线日志文件学习