Android自定义View

合集下载

Android实现侧滑菜单

Android实现侧滑菜单

Android实现侧滑菜单侧滑菜单的实现在很多应用中都有所体现。

例如:QQ侧滑、微信侧滑等等,几乎是各个领域中的应用都有所涉及。

与此同时,实现侧滑的方式也是比比皆是。

下面为大家介绍其中一种的实现方式:自定义View实现侧滑菜单。

效果展示:具体的使用自定义View实现之前先理解一下原始的实现原理:1、使用ViewGroup存放2个View,一个是Menu菜单,一个是显示内容的Content2、监听比比皆是onTouchEvent事件处理ACTION_MOVE中的leftMargin位置,从而改变menu菜单的滑动位置当ACTION_UP时,根据显示菜单的宽度,决定将其显示或隐藏动画效果:(1)使用Scroller这个辅助类实现动画效果(2)单起一个Thread(或Task)来改变leftMargin的大小来实现动画效果3、使用自定义View实现侧滑菜单的实现原理:(1)自定义HorizontalScrollView(可自动左右滑动)子类,重写构造方法、onMesure、onLayout、onTouchEvent方法。

[1] onMesure:决定内部View的宽和高wallper = (LinearLayout) getChildAt(0);// 获取menu(菜单布局)实例menu = (ViewGroup) wallper.getChildAt(0);// 获取content(内容布局)实例content = (ViewGroup) wallper.getChildAt(1);// 设置menu的宽度menu_width = menu.getLayoutParams().width = screen_width- menu_rightpadding;// 设置content的宽度content.getLayoutParams().width = screen_width;[2] onLayout:决定子View的放置位置// 为正值,表示为内容区域向左移动if (changed) {this.scrollTo(menu_width, 0);}[3]onTouchEvent:决定内部View的移动监听case MotionEvent.ACTION_UP:int scrollX = getScrollX();// 内容区域左侧多出来的部分--隐藏在左边的宽度if (scrollX>= menu_width / 2) {// smoothScrollTo隐藏(内容区域)效果相对缓和this.smoothScrollTo(menu_width, 0);isopen = false;} else {// 内容区域左边与屏幕合并this.smoothScrollTo(0, 0);isopen = true;}returntrue;[4]构造方法:(1)获取屏幕的宽度,以便于后面根据侧滑的比率判断是否显示子菜单;WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetricsoutMetrics = new DisplayMetrics();// 将当前窗口的信息放在DisplayMetrics中manager.getDefaultDisplay().getMetrics(outMetrics);screen_width = outMetrics.widthPixels;(2)将菜单栏距右侧距离dp转换为像素值px(自定义参数)menu_rightpadding = a.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(PLEX_UNIT_DIP, 50,context.getResources().getDisplayMetrics()));(2)引入自定义属性,允许用户自定义菜单距离屏幕右侧的边距[1] 书写xml文件<resources><attr name="rightPadding"format="dimension"></attr><declare-styleable name="SlidingMenu"><attr name="rightPadding"></attr></declare-styleable></resources>[2]布局中添加自定义属性的xmlnsxmlns:auto="/apk/res/com.example.fragment_horizontalscrollview"[3]构造方法中实现// 获取自定义的属性TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SlidingMenu, defStyle, 0);int n = a.getIndexCount();for (int i = 0; i< n; i++) {// 遍历所有属性int attr = a.getIndex(i);switch (attr) {case R.styleable.SlidingMenu_rightPadding:menu_rightpadding = a.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(PLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()));Break;default:break;}}(3)布局中引入自定义属性auto:rightPadding="100dp"(4)引入nineoldandroids-2.4.0.jar(提供较低版本兼容性)nineoldandroids-2.4.0.jar(5)主界面中调用切换方法。

Android自定义wheelview实现滚动日期选择器

Android自定义wheelview实现滚动日期选择器

Android⾃定义wheelview实现滚动⽇期选择器本⽂实例为⼤家分享了Android实现滚动⽇期选择器的具体代码,供⼤家参考,具体内容如下wheelview滚动效果的View这段时间需要⽤到⼀个时间选择器,但是不能使⽤⽇期对话框,因为它是筛选条件框架下的,只能是View!这个WheelView改造后可以达到要求!这个wheelview框架使⽤的类不多,就⼏个,还有⼀些资源⽂件。

我根据这个框架设计了⽇期的选择器。

主页⾯:第⼀种⽇期选择器页⾯:动态效果:使⽤:具体的实现是⼀个LoopView的类,这是⼀个继承View的类!理解LoopView的公开⽅法就可以了。

1.布局⽂件<LinearLayout xmlns:android="/apk/res/android" xmlns:app="/apk/res-auto"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#fff"><com.example.wheelview.loopview.LoopViewandroid:layout_marginTop="50dp"android:id="@+id/loopView"android:layout_width="match_parent"android:layout_height="150dp"app:awv_textsize="18"/></LinearLayout>2.控制代码package com.example.wheelview.activity;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.widget.Toast;import com.example.wheelview.R;import com.example.wheelview.loopview.LoopView;import com.example.wheelview.loopview.OnItemSelectedListener;import java.util.ArrayList;public class MyActivity extends Activity {private Toast toast;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);final LoopView loopView = (LoopView) findViewById(R.id.loopView);ArrayList<String> list = new ArrayList<String>();for (int i = 0; i < 15; i++) {list.add("item " + i);}//设置是否循环播放// loopView.setNotLoop();//滚动监听loopView.setListener(new OnItemSelectedListener() {@Overridepublic void onItemSelected(int index) {if (toast == null) {toast = Toast.makeText(MyActivity.this, "item " + index, Toast.LENGTH_SHORT);}toast.setText("item " + index);toast.show();}});//设置原始数据loopView.setItems(list);}}那个⽇期选择器就是使⽤三个LoopView结合⽽成的!LoopView类⾥⾯控制字体颜⾊和横线颜⾊的地⽅://中间选中的字体颜⾊:灰⾊:0xff313131,橙⾊:0xffec6f1acenterTextColor = typedArray.getInteger(R.styleable.androidWheelView_awv_centerTextColor, 0xffec6f1a);//没被选中的字体的颜⾊outerTextColor = typedArray.getInteger(R.styleable.androidWheelView_awv_outerTextColor, 0xffafafaf);//中间字体上下两条横线的颜⾊dividerColor = typedArray.getInteger(R.styleable.androidWheelView_awv_dividerTextColor, 0xffc5c5c5);其他的控制可以参考我的代码我的项⽬的代码:我的代码中有⼀个时间的⼯具类,可以很⽅便的取到任何时间,你也可以在⽇期选择器中多加⼀个按钮,设置到今天的⽇期。

Android自定义TextView实现文本内容自动调整字体大小

Android自定义TextView实现文本内容自动调整字体大小

Android⾃定义TextView实现⽂本内容⾃动调整字体⼤⼩最近做通讯录⼩屏机联系⼈姓名显⽰--长度超过边界字体变⼩/*** ⾃定义TextView,⽂本内容⾃动调整字体⼤⼩以适应TextView的⼤⼩* @author yzp*/public class AutoFitTextView extends TextView {private Paint mTextPaint;private float mTextSize;public AutoFitTextView(Context context) {super(context);}public AutoFitTextView(Context context, AttributeSet attrs) {super(context, attrs);}/*** Re size the font so the specified text fits in the text box assuming the* text box is the specified width.** @param text* @param textWidth*/private void refitText(String text, int textViewWidth) {if (text == null || textViewWidth <= 0)return;mTextPaint = new Paint();mTextPaint.set(this.getPaint());int availableTextViewWidth = getWidth() - getPaddingLeft() - getPaddingRight();float[] charsWidthArr = new float[text.length()];Rect boundsRect = new Rect();mTextPaint.getTextBounds(text, 0, text.length(), boundsRect);int textWidth = boundsRect.width();mTextSize = getTextSize();while (textWidth > availableTextViewWidth) {mTextSize -= 1;mTextPaint.setTextSize(mTextSize);textWidth = mTextPaint.getTextWidths(text, charsWidthArr);}this.setTextSize(PLEX_UNIT_PX, mTextSize);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);refitText(this.getText().toString(), this.getWidth());}}以上就是本⽂的全部内容,希望本⽂的内容对⼤家的学习或者⼯作能带来⼀定的帮助,同时也希望多多⽀持!。

Android自定义ImageView实现点击两张图片切换效果

Android自定义ImageView实现点击两张图片切换效果

Android⾃定义ImageView实现点击两张图⽚切换效果笔者在做⼀个项⽬中遇到的⼀个⼩阻碍,于是就实现了这个ImageView达到开发需求情景需求 > 点击实现图⽚的切换可能有⼈会说了,这还不简单?为ImageView设置点击事件,然后通过重写的onClick(View v)⽅法判断定义的某⼀个flag进⾏图⽚的切换,伪代码如下:private boolean flag;public void onClick(View v){if(flag){mImageView.setImageResource(R.drawable.xx1);}else{mImageView.setImageResource(R.drawable.xx2);}flag = !flag;}笔者连上⾯的代码知道写出来那为什么还要去⾃定义⼀个ImageView了?具体需求:两个ImageView之间实现单选效果我们试想下,⽬前两个ImageView通过上⾯的代码可能还好,只要在不同的事件中做出不同的判断就好了,但如果⼀但ImageView增多了了?A:你不知道⽤ RadioGroup+RadioButton 啊!B:是哦!我现在去试下。

……B:不⾏啊,虽然RadioButton可以实现,但不好做适配,我为RadioButton设置Drawable,不能居中,⽽且不能随着RadioButton的⼤⼩改变⽽改变,资源图⽚是多⼤就多⼤,显⽰区域不够就不能完全显⽰出来。

A:…?,额,是吗?这样啊!那我们就⾃定义⼀个ImageView来实现吧!B:为什么是⾃定义ImageView?⽽不是⾃定义RadioButton?A:⾃定义RadioButton实现ImageView的src属性⽐较复杂(等着正在看这博客的⼤神实现),⽽⾃定义ImageView来实现单选的属性⽐较好实现。

B:那怎么实现了?A:看代码,代码如下:attrs.xml <为⾃定义ImageView添加两个属性><?xml version="1.0" encoding="utf-8"?><resources><declare-styleable name="SelectorImageView"><attr name="selector_src" format="reference"/>//选中的src图⽚属性<attr name="checked" format="boolean"/></declare-styleable></resources>Class - SelectorImageView<此类实现了Checkable接⼝,这⾥没什么特殊功能,⽽只是利⽤此接⼝中的⽅法⽽已,不实现我们也可以⾃⼰写>public class SelectorImageView extends ImageView implements Checkable {private boolean isChecked;private Drawable mSelectorDrawable;private Drawable mDrawable;public SelectorImageView(Context context) {this(context, null);}public SelectorImageView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public SelectorImageView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);/**获取默认属性src的Drawable并⽤成员变量保存*/mDrawable = getDrawable();final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SelectorImageView);/**获取⾃定义属性selector_src的Drawable并⽤成员变量保存*/Drawable d = a.getDrawable(R.styleable.SelectorImageView_selector_src);mSelectorDrawable = d;/**获取⾃定义属性checked的值并⽤成员变量保存*/isChecked = a.getBoolean(R.styleable.SelectorImageView_checked, false);setChecked(isChecked);if (d != null && isChecked) {/**如果在布局中设置了selector_src与checked = true,我们就要设置ImageView的图⽚为mSelectorDrawable */ setImageDrawable(d);}a.recycle();}@Overridepublic void setImageDrawable(Drawable drawable) {super.setImageDrawable(drawable);}@Overridepublic void setChecked(boolean checked) {this.isChecked = checked;}@Overridepublic boolean isChecked() {return isChecked;}@Overridepublic void toggle() {/**此处依据是否选中来设置不同的图⽚*/if (isChecked()) {setImageDrawable(mSelectorDrawable);} else {setImageDrawable(mDrawable);}}public void toggle(boolean checked){/**外部通过调⽤此⽅法传⼊checked参数,然后把值传⼊给setChecked()⽅法改变当前的选中状态*/setChecked(checked);toggle();}}layout.xml<LinearLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"><com.qjay.adf.widget.SelectorImageViewandroid:id="@+id/iv"android:layout_width="100dp"android:layout_height="100dp"app:selector_src="@mipmap/checked"android:src="@mipmap/no_checked"/></LinearLayout>Activity Codepublic class MainActivity extends Activity {private SelectorImageView iv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);iv = (SelectorImageView) findViewById(R.id.iv);iv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {iv.toggle(!iv.isChecked());}});}}实现效果以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

【朝花夕拾】Android自定义View篇之(四)自定义View的三种实现方式及自定义属性使用介绍

【朝花夕拾】Android自定义View篇之(四)自定义View的三种实现方式及自定义属性使用介绍

【朝花⼣拾】Android⾃定义View篇之(四)⾃定义View的三种实现⽅式及⾃定义属性使⽤介绍前⾔尽管Android系统提供了不少控件,但是有很多酷炫效果仍然是系统原⽣控件⽆法实现的。

好在Android允许⾃定义控件,来弥补原⽣控件的不⾜。

但是在很多初学者看来,⾃定义View似乎很难掌握。

其中有很⼤⼀部分原因是我们平时看到的⾃定义View使⽤中,有多种形式,有的寥寥数笔,有的逻辑很复杂,有的直接继承View或ViewGroup,有的却直接继承系统的原⽣控件,有的可以直接使⽤系统定义的属性,⽽有的却⾃定义了⾃⼰的属性......所以不明⽩使⽤规则的开发者,很容易被这只“纸⽼虎”吓到。

实际上实现⾃定义View的⽅式,从整体上看,只分为三种:组合控件,继承控件,⾃绘控件。

然后就是根据需要来添加⾃定义的属性,就这么简单。

本⽂将会针对这4个⽅⾯进⾏详细的讲解。

主要内容如下:⼀、组合控件组合控件,顾名思义,就是将系统原有的控件进⾏组合,构成⼀个新的控件。

这种⽅式下,不需要开发者⾃⼰去绘制图上显⽰的内容,也不需要开发者重写onMeasure,onLayout,onDraw⽅法来实现测量、布局以及draw流程。

所以,在实现⾃定义view的三种⽅式中,这⼀种相对⽐较简单。

实际开发中,标题栏就是⼀个⽐较常见的例⼦。

因为在⼀个app的各个界⾯中,标题栏基本上是⼤同⼩异,复⽤率很⾼。

所以经常会将标题栏单独做成⼀个⾃定义view,在不同的界⾯直接引⼊即可,⽽不⽤每次都把标题栏布局⼀遍。

本节就⾃定义⼀个标题栏,包含标题和返回按钮两个控件,来介绍这种组合控件的实现⽅式。

1、定义标题栏布局⽂件定义标题栏的布局⽂件custom_title_view.xml,将返回按钮和标题⽂本进⾏组合。

这⼀步⽤于确定标题栏的样⼦,代码如下所⽰:1<?xml version="1.0" encoding="utf-8"?>2<RelativeLayout xmlns:android="/apk/res/android"3 android:layout_width="match_parent"4 android:layout_height="wrap_content"5 android:background="@android:color/holo_orange_light">6<Button7android:id="@+id/btn_left"8 android:layout_width="wrap_content"9 android:layout_height="wrap_content"10 android:layout_centerVertical="true"11 android:layout_marginLeft="5dp"12 android:text="Back"13 android:textColor="@android:color/white"/>1415<TextView16android:id="@+id/title_tv"17 android:layout_width="wrap_content"18 android:layout_height="wrap_content"19 android:layout_centerInParent="true"20 android:text="Title"21 android:textColor="@android:color/white"22 android:textSize="20sp"/>23</RelativeLayout>这个布局很简单,就不多说了。

Android开发自定义TextView省略号样式的方法

Android开发自定义TextView省略号样式的方法

Android开发⾃定义TextView省略号样式的⽅法本⽂实例讲述了Android开发⾃定义TextView省略号样式的⽅法。

分享给⼤家供⼤家参考,具体如下:在布局xml中设置textView的字段android:maxLines="2"android:ellipsize="end"字段之后,textview会⾃动压缩⾏数,并且对压缩掉的部分⽤...显⽰。

如果不想⽤...⽽想⽤。

或者... ...就需要⾃定义这个省略号的样式,不需要⾃定义控件,⽅法如下。

⾸先是布局⽂件<TextViewandroid:id="@+id/textView4"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:layout_centerHorizontal="true"android:maxLines="2"android:ellipsize="end"android:text="This is a text of TextView This is a text of TextView This is a text of TextView This is a text of TextView This is a text of TextView"android:textSize="20sp" />对textView进⾏代码控制protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);final TextView textView = (TextView)findViewById(R.id.textView4);Layout layout = textView.getLayout();//此时的layout为null,必须⽤观察者模式的回调函数来获取layoutSystem.out.println("layout是"+layout);//此处为nullViewTreeObserver observer = textView.getViewTreeObserver();observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {boolean isfirstRunning = true;@Overridepublic void onGlobalLayout() {//此⽅法会被调⽤两次,每执⾏⼀次settext就会执⾏⼀次,第⼀次是显⽰全部的⽂本,不加省略,第⼆次是加上省略,将会删减两次⽂本 // TODO Auto-generated method stubif(isfirstRunning==false)return;//如果不加这⼀⾏的条件,出来之后是完整单词+。

自定义view的基本流程

自定义view的基本流程

自定义view的基本流程1.自定义View的意义自定义View是开发Android应用的常见需求,它可以实现各种特殊的UI效果和交互效果。

有时候,自带的一些View无法满足我们的需求,而自定义一个View可以帮助我们实现想要的效果。

2.自定义View的基本流程要实现一个自定义View,通常需要经过以下基本流程:2.1创建自定义View类首先,我们需要创建一个自定义View的类,并继承自View或其子类,比如ImageView、TextView等。

在类中,我们可以重写onMeasure()、onLayout()和onDraw()等方法来实现自定义View的特殊行为。

2.2声明自定义View的属性如果我们希望在XML布局文件中使用自定义View,并可以在代码中设置属性值,就需要在类中声明自定义属性。

这可以通过在res/values/attrs.xml文件中定义属性集合来实现。

2.3实现自定义View的布局在onMeasure()方法中,我们可以指定自定义View在测量时占用的空间大小。

在onLayout()方法中,我们可以指定子View的位置。

2.4实现自定义View的绘制在onDraw()方法中,我们可以通过调用Canvas的API来实现自定义View的绘制效果。

例如,我们可以通过Path绘制自定义的图形,通过Paint设置绘制时的样式和颜色等。

2.5对自定义View进行测试最后,我们需要通过手动测试、单元测试、自动化UI测试等方式,对自定义View进行测试和验证。

3.自定义View的实例以下是一个简单的自定义View实例,用于显示一个可以按下和弹起的按钮:```public class MyButton extends View{private boolean isPressed=false;public MyButton(Context context){super(context);}public MyButton(Context context,AttributeSet attrs) {super(context,attrs);}@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);Paint paint=new Paint();paint.setColor(isPressed?Color.RED:Color.GREEN);canvas.drawRect(0,0,getWidth(),getHeight(), paint);}@Overridepublic boolean onTouchEvent(MotionEvent event){if(event.getAction()==MotionEvent.ACTION_DOWN) {isPressed=true;invalidate();return true;}else if(event.getAction()==MotionEvent.ACTION_UP){isPressed=false;invalidate();return true;}return super.onTouchEvent(event);}}```以上代码中,我们实现了一个MyButton类,当MyButton被按下时,它的背景颜色会变成红色,当MyButton被弹起时,它的背景颜色会回到绿色。

android 常见view的用法

android 常见view的用法

android 常见view的用法常见的Android View的用法有:1. TextView(文本视图):用于显示文本内容,可以设置字体、颜色、字体大小等属性。

2. ImageView(图片视图):用于显示图片,可以设置图片资源、缩放类型、背景等属性。

3. Button(按钮):用于触发点击事件,可以设置文本、背景、点击效果等属性。

4. EditText(编辑文本视图):用于输入文本内容,可以设置提示文本、输入类型、最大长度等属性。

5. RadioButton(单选按钮):用于在多个选项中选择一个,可以设置文本、选中状态等属性。

6. CheckBox(复选框):用于在多个选项中选择多个,可以设置文本、选中状态等属性。

7. ProgressBar(进度条):用于显示操作进度,可以设置进度值、样式、颜色等属性。

8. SeekBar(滑动条):用于选择数值范围,可以设置最小值、最大值、当前值等属性。

9. ListView(列表视图):用于显示大量数据列表,可以自定义每一项的布局和交互。

10. GridView(网格视图):用于显示数据的表格布局,可以自定义每个单元格的布局和交互。

11. RecyclerView(可复用列表视图):Android的推荐使用的列表视图,功能更强大、性能更优。

12. WebView(网页视图):用于显示网页内容,可以加载本地或远程网页。

13. ScrollView(滚动视图):用于包裹超出屏幕大小的内容,并通过滑动来查看全部内容。

14. LinearLayout(线性布局):用于按照水平或垂直方向排列子视图。

15. RelativeLayout(相对布局):用于按照相对位置摆放子视图,灵活性更高。

16. FrameLayout(帧布局):用于叠加子视图,通常用于显示单个子视图或切换视图。

这些是Android中常见的View,开发者可以根据实际需求选择合适的View并设置相应的属性,实现各种不同的界面效果。

Android中自定义样式与View的构造函数中的第三个参数defStyle的意义

Android中自定义样式与View的构造函数中的第三个参数defStyle的意义

零、序一、自定义Style二、在XML中为属性声明属性值1. 在layout中定义属性2. 设置Style3. 通过Theme指定三、在运行时获取属性值1. View的第三个构造函数的第三个参数defStyle2. obtailStyledAttributes3. Example四、结论与代码下载零、序系统自带的View可以在xml中配置属性,对于写的好的Custom View同样可以在xml中配置属性,为了使自定义的View的属性可以在xml中配置,需要以下4个步骤:1.1.通过<declare-styleable>为自定义View添加属性2.在xml中为相应的属性声明属性值3.在运行时(一般为构造函数)获取属性值4.将获取到的属性值应用到View怎么将获取到的属性值应用到View就不用说了,自己定义的属性什么用处自己肯定是清楚的,所以接下来看一下前三点。

通过<declare-styleable>元素声明Custom View需要的属性即可,下面是一个例子,文件是res/values/attrs.xml<?xml version="1.0" encoding="utf-8"?><resources><declare-styleable name="Customize"><attr name="attr_one" format="string"/><attr name="attr_two" format="string"/><attr name="attr_three" format="string"/><attr name="attr_four" format="string"/></declare-styleable><attr name="CustomizeStyle" format="reference"/></resources>在上述xml中,我们声明了Customize与CustomizeSyle,Customize包含了attr_one、attr_two、attr_three与attr_four四个attribute,CustomizeStyle也是一个attribute,但是却没有声明在declare-styleable中。

Android自定义View仿探探卡片滑动效果

Android自定义View仿探探卡片滑动效果

Android⾃定义View仿探探卡⽚滑动效果Android⾃定义View仿探探卡⽚滑动这种效果⽹上有很多⼈已经讲解了实现思路,⼤多都⽤的是RecyclerView来实现的,但是我们今天来换⼀种实现思路,只⽤⼀个⾃定义的ViewGroup来搞定这个实现。

下⾯我们先看⼀下实现的效果:这个⾃定义View⽤法也很简单,⾸先从github上下载或者fork这个项⽬,在布局中添加:<com.liyafeng.view.swipecard.SwipeCardLayoutandroid:id="@+id/scl_layout"android:layout_width="match_parent"android:layout_height="match_parent"/>是的,没有⼀点废话,⾃定义属性可以根据⾃⼰的需求来添加。

下⾯是代码中初始化:public class SwipeCardActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_swipe_card);SwipeCardLayout scl_layout=(SwipeCardLayout)findViewById(R.id.scl_layout);Queue<CardEntity> data = new LinkedList<>();CardEntity cardEntity1 = new CardEntity(R.drawable.f1, "这⾥是美丽的湖畔");CardEntity cardEntity2 = new CardEntity(R.drawable.f2, "这⾥游泳⽐较好");CardEntity cardEntity3 = new CardEntity(R.drawable.f3, "向往的蓝天⽩云");CardEntity cardEntity4 = new CardEntity(R.drawable.f4, "繁华的都市");CardEntity cardEntity5 = new CardEntity(R.drawable.f5, "草原象征着理想");data.add(cardEntity1);data.add(cardEntity2);data.add(cardEntity3);data.add(cardEntity4);data.add(cardEntity5);scl_layout.setAdapter(new SwipeCardLayout.CardAdapter<CardEntity>(data) {@Overridepublic View bindLayout() {return LayoutInflater.from(SwipeCardActivity.this).inflate(yout.card_layout,null);}@Overridepublic void bindData(CardEntity data, View convertView) {ImageView iv_card = (ImageView)convertView.findViewById(R.id.iv_card);TextView tv_card = (TextView) convertView.findViewById(_card);iv_card.setImageResource(data.resId);tv_card.setText(data.content);}});scl_layout.setOnSwipeListener(new SwipeCardLayout.OnSwipeListener() {@Overridepublic void onSwipe(int type) {switch (type) {case SwipeCardLayout.TYPE_RIGHT:Toast.makeText(SwipeCardActivity.this, "right", Toast.LENGTH_SHORT).show();break;case SwipeCardLayout.TYPE_LEFT:Toast.makeText(SwipeCardActivity.this, "left", Toast.LENGTH_SHORT).show();break;}}});}class CardEntity {public CardEntity(int resId, String content) {this.resId = resId;this.content = content;}public int resId;public String content;}}这⾥必须要⽤⼀个队列来添加数据,显⽰的顺序就是队列的顺序。

Android自定义view之仿支付宝芝麻信用仪表盘

Android自定义view之仿支付宝芝麻信用仪表盘

Android自定义view之仿支付宝芝麻信用仪表盘Android自定义view之仿支付宝芝麻信用仪表盘自定义view练习仿支付宝芝麻信用的仪表盘对比图:首先是自定义一些属性,可自己再添加,挺基础的,上代码[html] view plain copy<?xml version="1.0" encoding="utf-8"?><resources><declare-styleable name="RoundIndicatorView"><!--最大数值--><attr name="maxNum" format="integer"/><!--圆盘起始角度--><attr name="startAngle" format="integer"/><!--圆盘扫过的角度--><attr name="sweepAngle" format="integer"/></declare-styleable></resources>接着在构造方法里初始化自定义属性和画笔:[java] view plain copyprivate void initAttr(AttributeSet attrs) {TypedArray array =context.obtainStyledAttributes(attrs,R.styleable.RoundIndicatorView);maxNum = array.getInt(R.styleable.RoundIndicatorView_maxNum,500);startAngle =array.getInt(R.styleable.RoundIndicatorView_startAngle,160);sweepAngle =array.getInt(R.styleable.RoundIndicatorView_sweepAngle,220);//内外圆弧的宽度sweepInWidth = dp2px(8);sweepOutWidth = dp2px(3);array.recycle();}private void initPaint() {paint = new Paint(Paint.ANTI_ALIAS_FLAG);paint.setDither(true);paint.setStyle(Paint.Style.STROKE);paint.setColor(0xffffffff);paint_2 = new Paint(Paint.ANTI_ALIAS_FLAG);paint_3 = new Paint(Paint.ANTI_ALIAS_FLAG);paint_4 = new Paint(Paint.ANTI_ALIAS_FLAG); }接下来重写onMeasure,也是比较简单,对于不是确定值的直接给定300*400的大小:[java] view plain copy@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int wSize = MeasureSpec.getSize(widthMeasureSpec);int wMode = MeasureSpec.getMode(widthMeasureSpec);int hSize = MeasureSpec.getSize(heightMeasureSpec);int hMode = MeasureSpec.getMode(heightMeasureSpec);if (wMode == MeasureSpec.EXACTLY ){mWidth = wSize;}else {mWidth =dp2px(300);}if (hMode == MeasureSpec.EXACTLY ){mHeight= hSize;}else {mHeight =dp2px(400);}setMeasuredDimension(mWidth,mHeight);}核心部分onDraw来了,注意圆的半径不要在构造方法里就去设置,那时候是得不到view的宽高值的,所以我在onDraw方法里设置半径,默认就view宽度的1/4吧。

android自定义ImageView实现缩放,回弹效果

android自定义ImageView实现缩放,回弹效果

android自定义ImageView实现缩放,回弹效果androidImageview缩放回弹话不多说上代码:MainActivity.javapublic class MainActivity extends Activity{private LinearLayout ll_viewArea;private youtParams parm;private ViewArea viewArea;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//去除titlerequestWindowFeature(Window.FEATURE_NO_TITLE);//去掉Activity上面的状态栏getWindow().setFlags(youtParams.FLAG_FULLSCREEN,youtParams. FLAG_FULLSCREEN);setContentView(yout.main);ll_viewArea = (LinearLayout) findViewById(R.id.ll_viewArea); parm = newyoutParams(youtParams.FILL_PARENT, youtParams.FILL_PARENT);viewArea = newViewArea(MainActivity.this,R.drawable.psu); //自定义布局控件,用来初始化并存放自定义imageViewll_viewArea.addView(viewArea,parm);}}这段代码中要注意的问题是去掉title和状态栏两句代码必须放到setContentView(yout.main);话的前面。

而且这两句话必须有,因为后面计算回弹距离是根据全屏计算的(我的i9000就是480x800),如果不去掉title 和状态栏,后面的回弹会有误差,总是回弹不到想要的位置。

Android自定义view中实现LifecycleOwner

Android自定义view中实现LifecycleOwner

Android自定义view中实现LifecycleOwner Android提供了一个强大的架构组件,Lifecycle,用于帮助开发者在应用程序的不同组件(如Activity、Fragment、Service等)生命周期发生变化时执行相应的操作。

然而,在自定义View中使用Lifecycle组件并不是那么直接。

在本文中,将介绍如何在自定义View中实现LifecycleOwner接口。

LifecycleOwner接口是Lifecycle组件的核心接口之一,它提供了一个Lifecycle对象,用于观察其生命周期状态。

在Android中,Activity和Fragment实现了LifecycleOwner接口,并且它们的生命周期状态可以直接通过lifecycle对象获取。

但是,自定义View并没有直接实现该接口,这意味着我们需要自己实现它。

要在自定义View中实现LifecycleOwner接口,我们首先需要创建一个LifecycleRegistry对象,并在相应的生命周期方法中更新其状态。

在自定义View的构造方法中创建一个LifecycleRegistry对象,并在构造方法中调用init方法进行初始化。

```kotlinprivate val lifecycleRegistry: LifecycleRegistryconstructor(context: Context) : this(context, null)constructor(context: Context, attrs: AttributeSet?) :super(context, attrs)lifecycleRegistry = LifecycleRegistry(this)lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED}private fun ini//进行一些初始化操作lifecycleRegistry.currentState = Lifecycle.State.CREATED }override fun onAttachedToWindosuper.onAttachedToWindowlifecycleRegistry.currentState = Lifecycle.State.STARTED }override fun onDetachedFromWindolifecycleRegistry.currentState = Lifecycle.State.DESTROYED super.onDetachedFromWindow}override fun onStarsuper.onStartlifecycleRegistry.currentState = Lifecycle.State.STARTED }override fun onStolifecycleRegistry.currentState = Lifecycle.State.CREATEDsuper.onStop}override fun getLifecycle(: Lifecyclereturn lifecycleRegistry}```在上述代码中,我们创建了一个LifecycleRegistry对象,并在构造方法和相应的生命周期方法中更新其状态。

自定义View实现三角形(正三角,倒三角)

自定义View实现三角形(正三角,倒三角)

⾃定义View实现三⾓形(正三⾓,倒三⾓)⾃定义的属性如下:<declare-styleable name="TriangleView"><!--模式--><attr name="tlv_mode"><!--倒三⾓--><enum name="inverted" value="0"/><!--正三⾓--><enum name="regular" value="1"/></attr><!--颜⾊--><attr name="tlv_color" format="color|reference"/></declare-styleable>具体代码如下:import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.support.annotation.IntDef;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.View;import ng.annotation.Retention;import ng.annotation.RetentionPolicy;/*** 三⾓形*/public class TriangleView extends View{private Paint paint;private Path path;private int color;private int mode;private final int DEFAULT_WIDTH=48;private final int DEFAULT_HEIGHT=24;private int width = 0;private int height =0;/*** 倒三⾓*/public static final int INVERTED = 0;/*** 正三⾓*/public static final int REGULAR = 1;@IntDef({INVERTED, REGULAR})@Retention(RetentionPolicy.SOURCE)public @interface ShapeMode {}public TriangleView(Context context) {this(context,null);}public TriangleView(Context context, @Nullable AttributeSet attrs) {this(context,attrs,0);}public TriangleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context,attrs);}private void init(Context context,AttributeSet attrs){TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TriangleView);color = typedArray.getColor(R.styleable.TriangleView_tlv_color, Color.BLACK);mode = typedArray.getInt(R.styleable.TriangleView_tlv_mode, INVERTED);typedArray.recycle();paint = new Paint();paint.setColor(color);paint.setAntiAlias(true);paint.setStyle(Paint.Style.FILL);path= new Path();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec);width = measureSize(widthMeasureSpec, DEFAULT_WIDTH);height = measureSize(heightMeasureSpec, DEFAULT_HEIGHT);setMeasuredDimension(width, height);}private int measureSize(int measureSpec, int defaultSize) {int newSize = 0;int mode = MeasureSpec.getMode(measureSpec);int size = MeasureSpec.getSize(measureSpec);switch (mode) {case MeasureSpec.AT_MOST:newSize = Math.min(size, defaultSize);break;case MeasureSpec.EXACTLY:newSize = size;break;case MeasureSpec.UNSPECIFIED:newSize = defaultSize;break;}return newSize;}public void setColor(int color){this.color=color;paint.setColor(color);invalidate();}public void setMode(@ShapeMode int mode){this.mode=mode;invalidate();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawTriangle(canvas);}private void drawTriangle(Canvas canvas) {if(mode==INVERTED) {path.moveTo(0f, 0f);path.lineTo(width, 0f);path.lineTo(width / 2.0f, height);}else {path.moveTo(width/2.0f,0f);path.lineTo(0,height);path.lineTo(width,height);}path.close();canvas.drawPath(path, paint);}}。

Android自定义ViewGroup实现带箭头的圆角矩形菜单

Android自定义ViewGroup实现带箭头的圆角矩形菜单

Android⾃定义ViewGroup实现带箭头的圆⾓矩形菜单本⽂和⼤家⼀起做⼀个带箭头的圆⾓矩形菜单,⼤概长下⾯这个样⼦:要求顶上的箭头要对准菜单锚点,菜单项按压反⾊,菜单背景⾊和按压⾊可配置。

最简单的做法就是让UX给个三⾓形的图⽚往上⼀贴,但是转念⼀想这样是不是太low了点,⽽且不同分辨率也不太好适配,⼲脆⾃定义⼀个ViewGroup吧!⾃定义ViewGroup其实很简单,基本都是按⼀定的套路来的。

⼀、定义⼀个attrs.xml就是声明⼀下你的这个⾃定义View有哪些可配置的属性,将来使⽤的时候可以⾃由配置。

这⾥声明了7个属性,分别是:箭头宽度、箭头⾼度、箭头⽔平偏移、圆⾓半径、菜单背景⾊、阴影⾊、阴影厚度。

<resources><declare-styleable name="ArrowRectangleView"><attr name="arrow_width" format="dimension" /><attr name="arrow_height" format="dimension" /><attr name="arrow_offset" format="dimension" /><attr name="radius" format="dimension" /><attr name="background_color" format="color" /><attr name="shadow_color" format="color" /><attr name="shadow_thickness" format="dimension" /></declare-styleable></resources>⼆、写⼀个继承ViewGroup的类,在构造函数中初始化这些属性这⾥需要⽤到⼀个obtainStyledAttributes()⽅法,获取⼀个TypedArray对象,然后就可以根据类型获取相应的属性值了。

深入了解view4

深入了解view4

Android自定义View的实现方法,带你一步步深入了解View(四)不知不觉中,带你一步步深入了解View系列的文章已经写到第四篇了,回顾一下,我们一共学习了LayoutInflater的原理分析、视图的绘制流程、视图的状态及重绘等知识,算是把View中很多重要的知识点都涉及到了。

如果你还没有看过我前面的几篇文章,建议先去阅读一下,多了解一些原理方面的东西。

之前我有承诺过,会在View这个话题上多写几篇博客,讲一讲View的工作原理,以及自定义View的方法。

现在前半部分的承诺已经如约兑现了,那么今天我就要来兑现后面部分的承诺,讲一讲自定义View的实现方法,同时这也是带你一步步深入了解View系列的完结篇。

一些接触Android不久的朋友对自定义View都有一丝畏惧感,总感觉这是一个比较高级的技术,但其实自定义View并不复杂,有时候只需要简单几行代码就可以完成了。

如果说要按类型来划分的话,自定义View的实现方式大概可以分为三种,自绘控件、组合控件、以及继承控件。

那么下面我们就来依次学习一下,每种方式分别是如何自定义View 的。

一、自绘控件自绘控件的意思就是,这个View上所展现的内容全部都是我们自己绘制出来的。

绘制的代码是写在onDraw()方法中的,而这部分内容我们已经在Android视图绘制流程完全解析,带你一步步深入了解View(二)中学习过了。

下面我们准备来自定义一个计数器View,这个View可以响应用户的点击事件,并自动记录一共点击了多少次。

新建一个CounterView继承自View,代码如下所示:[java]view plaincopy1.public class CounterView extends View implements OnClickListener {2.3.private Paint mPaint;4.5.private Rect mBounds;6.7.private int mCount;8.9.public CounterView(Context context, AttributeSet attrs) {10.super(context, attrs);11. mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);12. mBounds = new Rect();13. setOnClickListener(this);14. }15.16.@Override17.protected void onDraw(Canvas canvas) {18.super.onDraw(canvas);19. mPaint.setColor(Color.BLUE);20. canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);21. mPaint.setColor(Color.YELLOW);22. mPaint.setTextSize(30);23. String text = String.valueOf(mCount);24. mPaint.getTextBounds(text, 0, text.length(), mBounds);25.float textWidth = mBounds.width();26.float textHeight = mBounds.height();27. canvas.drawText(text, getWidth() / 2 - textWidth / 2, getHeight() /228. + textHeight / 2, mPaint);29. }30.31.@Override32.public void onClick(View v) {33. mCount++;34. invalidate();35. }36.37.}可以看到,首先我们在CounterView的构造函数中初始化了一些数据,并给这个View的本身注册了点击事件,这样当CounterView被点击的时候,onClick()方法就会得到调用。

android gridview的用法

android gridview的用法

android gridview的用法Android GridView的用法在Android应用程序开发中,GridView是一个非常有用的组件,用于显示类似表格的数据,并提供了许多自定义选项。

本文将介绍GridView的用法,并逐步讲解如何使用它来创建一个基本的网格布局。

1. 创建一个新的Android项目首先,打开Android Studio并创建一个新的Android项目。

选择一个项目名称和位置,然后选择适当的API级别和设备配置。

2. 准备布局文件在res/layout目录下创建一个新的布局文件,命名为activity_main.xml。

在此文件中,使用GridLayout作为根布局,并添加一些必要的属性。

xml<GridLayoutxmlns:android="android:id="@+id/gridLayout"android:layout_width="match_parent"android:layout_height="match_parent"android:columnCount="3"android:rowCount="3"></GridLayout>在此布局中,我们使用GridLayout作为根布局,并指定了columnCount 和rowCount属性来定义网格的行数和列数。

3. 创建GridView适配器创建一个新的Java类文件,命名为GridAdapter。

在该类中,继承BaseAdapter并实现必要的方法。

javapublic class GridAdapter extends BaseAdapter {private Context context;private List<Integer> data;public GridAdapter(Context context, List<Integer> data) {this.context = context;this.data = data;}@Overridepublic int getCount() {return data.size();}@Overridepublic Integer getItem(int position) {return data.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ImageView imageView;if (convertView == null) {imageView = new ImageView(context);imageView.setLayoutParams(newyoutParams(150, 150));imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);} else {imageView = (ImageView) convertView;}imageView.setImageResource(data.get(position));return imageView;}}在此适配器中,我们使用了一个ImageView作为网格中的单个项,通过设置布局参数和缩放模式来自定义它。

Android自定义view实现日历打卡签到

Android自定义view实现日历打卡签到

Android⾃定义view实现⽇历打卡签到本⽂实例为⼤家分享了Android⾃定义view实现⽇历打卡签到的具体代码,供⼤家参考,具体内容如下1.说明⾃⼰写⼀个view实现每天签到的功能,设置背景图⽚2.效果图3.主界⾯package com.example.myapplication30;import androidx.appcompat.app.AppCompatActivity;import android.annotation.SuppressLint;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.TextView;import java.util.ArrayList;import java.util.Calendar;import java.util.List;public class MainActivity extends AppCompatActivity {//参考⽹址:https:///MacaoPark/article/details/102069775private TextView mTvDaySum;private TextView mTvMonth;private SignView mCvCalendar;private List<SignEntity> data;private Calendar calendar;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);mTvDaySum = findViewById(R.id.punch_tv_day_sum);mTvMonth = findViewById(R.id.punch_tv_month);mCvCalendar = findViewById(R.id.punch_cv_calendar);}@Overrideprotected void onStart() {super.onStart();onReady();}@SuppressLint("SetTextI18n")private void onReady() {calendar = Calendar.getInstance();int year = calendar.get(Calendar.YEAR);int month = calendar.get(Calendar.MONTH);//int date = calendar.get(Calendar.DATE);int dayOfMonthToday = calendar.get(Calendar.DAY_OF_MONTH);List<SignDate> signDates = new ArrayList<>();signDates.add(new SignDate(2021, 5, 1, true));signDates.add(new SignDate(2021, 5, 2, true));signDates.add(new SignDate(2021, 5, 3, true));signDates.add(new SignDate(2021, 5, 4, true));signDates.add(new SignDate(2021, 5, 5, true));mTvDaySum.setText("本期连续登录\t"+signDates.size()+"\t天");mTvMonth.setText(year+"年"+getResources().getStringArray(R.array.month_array)[month]+"\t"+dayOfMonthToday+"⽇"); data = new ArrayList<>();for (int i = 1; i <= dayOfMonthToday; i++) {SignEntity signEntity = new SignEntity();if (i == dayOfMonthToday) {signEntity.setDayType(2);} else {signEntity.setDayType(1);}for (int j = 0; j < signDates.size(); j++) {if (signDates.get(j).getDay() == i) {signEntity.setDayType(0);break;} else if (dayOfMonthToday == i) {signEntity.setDayType(2);} else {signEntity.setDayType(1);}}data.add(signEntity);}SignAdapter signAdapter = new SignAdapter(data);mCvCalendar.setAdapter(signAdapter);}}4.适配器package com.example.myapplication30;import java.util.List;/*** SignAdapter* Created by E.M on 2016/4/21.*/public class SignAdapter extends CalendarAdapter {private List<SignEntity> data;public SignAdapter(List<SignEntity> data) {this.data = data;}@Overridepublic SignView.DayType getType(int dayOfMonth) {return SignView.DayType.valueOf(data.get(dayOfMonth - 1).getDayType());}}5.⾃定义viewpackage com.example.myapplication30;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.BitmapShader;import android.graphics.Canvas;import android.graphics.Color;import poseShader;import android.graphics.LinearGradient;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PorterDuff;import android.graphics.RadialGradient;import android.graphics.Rect;import android.graphics.Shader;import android.graphics.SweepGradient;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import java.util.Calendar;/*** 签到⽇历控件* Created by E.M on 2016/4/20.*/public class SignView extends View {private static final String[] WEEK_MARK = {"⼀", "⼆", "三", "四", "五", "六", "⽇"}; private static final int MAX_COLUMN = 7;/*** 周内*/private static final int COLOR_MARKER_WEEKDAY = 0xFF999999;private static final int COLOR_MARKER_WEEKEND = 0xFF1B89CD;/*** 已签到背景⾊*///private static final int COLOR_BACKGROUND_HIGHLIGHT = 0xFFFF0000;/*** 未签到背景⾊*/private static final int COLOR_BACKGROUND_NORMAL = 0xFF9C9C9C;/*** 等待签到背景⾊*/private static final int COLOR_BACKGROUND_WAIT = 0xFFFE7471;/*** 已签到⽂字颜⾊*/private static final int COLOR_TEXT_HIGHLIGHT = 0xFFFFFFFF;/*** 未签到⽂字颜⾊*/private static final int COLOR_TEXT_NORMAL = 0xFF606060;// /**// * 不可⽤⽂字颜⾊// */// private static final int COLOR_TEXT_DISABLED = 0xFFD4D4D4;private static final int MARKER_TEXT_SIZE = 40;private static final int CELL_TEXT_SIZE = 40;private static final int VERTICAL_SPACE = 51;private static final int VERTICAL_MARGIN = 62;private static final int HORIZONTAL_MARGIN = 39;private static final int CELL_SIZE = 80;private static final int WAIT_LINE_SIZE = 14;private int dayOfMonthToday;private int markerTextY;private int verticalCellTop;private int sumDayOfMonth;private int daysOfFirstWeek;private int horizontalSpace;private int deltaTextCellY;private int deltaTextMarkerY;private int verticalSpace;private int verticalMargin;private int horizontalMargin;private int cellSize;private int waitLineSize;private Path waitPath;private Rect waitRect;private Paint paintWeekday;private Paint paintWeekend;private Paint paintTextNormal;private Paint paintTextHighlight;private Paint paintBackgroundWait;private Paint paintBackgroundNormal;private Paint paintBackgroundHighlight;private CalendarAdapter adapter;public SignView(Context context) {this(context, null);}public SignView(Context context, AttributeSet attrs) {this(context, attrs, -1);}public SignView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initResolution();initPaint();initData();}private void initResolution() {// resolutionUtil = ResolutionUtil.getInstance();// verticalSpace = resolutionUtil.formatVertical(VERTICAL_SPACE);// verticalMargin = resolutionUtil.formatVertical(VERTICAL_MARGIN);// horizontalMargin = resolutionUtil.formatHorizontal(HORIZONTAL_MARGIN); // cellSize = resolutionUtil.formatVertical(CELL_SIZE);// waitLineSize = resolutionUtil.formatVertical(WAIT_LINE_SIZE);verticalSpace = VERTICAL_SPACE;verticalMargin = VERTICAL_MARGIN;horizontalMargin = HORIZONTAL_MARGIN;cellSize = CELL_SIZE;waitLineSize = WAIT_LINE_SIZE;}private void initPaint() {// int markerTextSize = resolutionUtil.formatVertical(MARKER_TEXT_SIZE); // int cellTextSize = resolutionUtil.formatVertical(CELL_TEXT_SIZE);int markerTextSize = MARKER_TEXT_SIZE;int cellTextSize = CELL_TEXT_SIZE;paintWeekday = new Paint();paintWeekday.setAntiAlias(true);paintWeekday.setColor(COLOR_MARKER_WEEKDAY);paintWeekday.setTextSize(markerTextSize);paintWeekday.setTextAlign(Paint.Align.CENTER);paintWeekend = new Paint();paintWeekend.setAntiAlias(true);paintWeekend.setColor(COLOR_MARKER_WEEKEND);paintWeekend.setTextSize(markerTextSize);paintWeekend.setTextAlign(Paint.Align.CENTER);paintTextNormal = new Paint();paintTextNormal.setAntiAlias(true);paintTextNormal.setColor(COLOR_TEXT_NORMAL);paintTextNormal.setTextSize(cellTextSize);paintTextNormal.setTextAlign(Paint.Align.CENTER);paintTextHighlight = new Paint();paintTextHighlight.setAntiAlias(true);paintTextHighlight.setColor(COLOR_TEXT_HIGHLIGHT);paintTextHighlight.setTextSize(cellTextSize);paintTextHighlight.setTextAlign(Paint.Align.CENTER);paintBackgroundWait = new Paint();paintBackgroundWait.setAntiAlias(true);paintBackgroundWait.setColor(COLOR_BACKGROUND_WAIT);paintBackgroundWait.setStrokeWidth(2);paintBackgroundWait.setStyle(Paint.Style.STROKE);paintBackgroundNormal = new Paint();paintBackgroundNormal.setAntiAlias(true);paintBackgroundNormal.setColor(COLOR_BACKGROUND_NORMAL);paintBackgroundNormal.setStrokeWidth(2);paintBackgroundNormal.setStyle(Paint.Style.STROKE);paintBackgroundHighlight = new Paint();paintBackgroundHighlight.setAntiAlias(true);paintBackgroundHighlight.setStrokeWidth(2);paintBackgroundHighlight.setStyle(Paint.Style.FILL);//颜⾊//paintBackgroundHighlight.setColor(COLOR_BACKGROUND_HIGHLIGHT);//多种颜⾊数组//int[] colors = {Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW,Color.MAGENTA};//float[] position = {0f, 0.2f, 0.4f, 0.6f, 1.0f};//Shader shader1 = new LinearGradient(100,850,600,850,colors,position,Shader.TileMode.CLAMP);//paintBackgroundHighlight.setShader(shader1);//设置背景图⽚/* Bitmap placeholder = BitmapFactory.decodeResource(getResources(), R.mipmap.small);Shader shader1 = new BitmapShader(placeholder, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); paintBackgroundHighlight.setShader(shader1);*/}private void initData() {Paint.FontMetricsInt fmiMarker = paintWeekday.getFontMetricsInt();deltaTextMarkerY = -(fmiMarker.bottom - fmiMarker.top) / 2 - fmiMarker.top;markerTextY = verticalMargin + cellSize / 2;Paint.FontMetricsInt fmiCell = paintTextNormal.getFontMetricsInt();deltaTextCellY = -(fmiCell.bottom - fmiCell.top) / 2 - fmiCell.top;verticalCellTop = verticalMargin + cellSize;Calendar calendarToday = Calendar.getInstance();dayOfMonthToday = calendarToday.get(Calendar.DAY_OF_MONTH);int dayOfWeek;sumDayOfMonth = calendarToday.getActualMaximum(Calendar.DAY_OF_MONTH);Calendar calendarFirstDay = Calendar.getInstance();calendarFirstDay.set(Calendar.DAY_OF_MONTH, 1);dayOfWeek = calendarFirstDay.get(Calendar.DAY_OF_WEEK);if (dayOfWeek == Calendar.SUNDAY) {dayOfWeek = 7;} else {dayOfWeek = dayOfWeek - 1;}daysOfFirstWeek = MAX_COLUMN - dayOfWeek + 1;}private void createWaitBackground(int topX, int topY) {waitPath = new Path();waitPath.moveTo(topX, topY + waitLineSize);waitPath.lineTo(topX, topY);waitPath.lineTo(topX + waitLineSize, topY);waitPath.moveTo(topX + cellSize - waitLineSize, topY + cellSize);waitPath.lineTo(topX + cellSize, topY + cellSize);waitPath.lineTo(topX + cellSize, topY + cellSize - waitLineSize);waitRect = new Rect(topX, topY, topX + cellSize, topY + cellSize);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);horizontalSpace = (w - MAX_COLUMN * cellSize - horizontalMargin * 2) / (MAX_COLUMN - 1);}@Overridepublic void draw(Canvas canvas) {super.draw(canvas);drawWeekMark(canvas);drawCellsBackground(canvas);drawCells(canvas);}private void drawWeekMark(Canvas canvas) {int y = markerTextY + deltaTextMarkerY;for (int i = 0; i < 7; i++) {int x = horizontalMargin + i * (horizontalSpace + cellSize)+ cellSize / 2;if (i < 5) {canvas.drawText(WEEK_MARK[i], x, y, paintWeekday);} else {canvas.drawText(WEEK_MARK[i], x, y, paintWeekend);}}}private void drawCellsBackground(Canvas canvas) {for (int i = 1; i <= dayOfMonthToday; i++) {drawCellBackground(canvas, i, getColumnIndex(i), getRowIndex(i));}}/*** 根据⾏列序号绘制⽇期背景** @param canvas 画布* @param dayOfMonth ⽇期* @param column 列序号* @param row ⾏序号*/private void drawCellBackground(Canvas canvas, int dayOfMonth, int column, int row) {int x = horizontalMargin + column * (horizontalSpace + cellSize)+ cellSize / 2;int y = verticalCellTop + verticalSpace * (row + 1) + cellSize * row + cellSize / 2;if (adapter != null) {DayType dayType = adapter.getType(dayOfMonth);switch (dayType) {case WAITING:if (waitPath == null) {createWaitBackground(x - cellSize / 2, y - cellSize / 2);}canvas.drawPath(waitPath, paintBackgroundWait);break;case SIGNED:// canvas.drawCircle(x, y, cellSize/2, paintBackgroundHighlight);// canvas.drawRect(x - 60, y - 60, x + 60, y + 60, paintBackgroundHighlight);// 正⽅形// Bitmap placeholder = BitmapFactory.decodeResource(getResources(), R.mipmap.purtest);// canvas.drawBitmap(placeholder,);wCircle(x, y, cellSize/2, paintBackgroundHighlight);canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.small3),x-40, y-40 , paintBackgroundHighlight); break;default:canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal);break;}} else {canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal);}}private void drawCells(Canvas canvas) {for (int i = 1; i <= sumDayOfMonth; i++) {drawCell(canvas, i, getColumnIndex(i), getRowIndex(i));}}/*** 根据⾏列序号绘制⽇期** @param canvas 画布* @param dayOfMonth ⽇期* @param column 列序号* @param row ⾏序号*/private void drawCell(Canvas canvas, int dayOfMonth, int column, int row) {int x = horizontalMargin + column * (horizontalSpace + cellSize)+ cellSize / 2;int y = verticalCellTop + verticalSpace * (row + 1) + cellSize * row + cellSize / 2+ deltaTextCellY;if (adapter != null && dayOfMonth <= dayOfMonthToday) {DayType dayType = adapter.getType(dayOfMonth);Paint paint;switch (dayType) {case SIGNED:paint = paintTextHighlight;break;default:paint = paintTextNormal;break;}canvas.drawText(String.valueOf(dayOfMonth), x, y, paint);} else {canvas.drawText(String.valueOf(dayOfMonth), x, y, paintTextNormal);}}/*** 获取列序号** @param dayOfMonth ⽇期* @return 列序号*/private int getColumnIndex(int dayOfMonth) {Calendar calendar = Calendar.getInstance();calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);if (dayOfWeek == Calendar.SUNDAY) {dayOfWeek = 6;} else {dayOfWeek = dayOfWeek - 2;}return dayOfWeek;}/*** 获取⾏序号** @param dayOfMonth ⽇期* @return ⾏序号*/private int getRowIndex(int dayOfMonth) {float weight = (dayOfMonth - daysOfFirstWeek) / (MAX_COLUMN * 1f);double rowIndexDouble = Math.abs(Math.ceil(weight));return (int) rowIndexDouble;}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_UP) {float x = event.getX();float y = event.getY();if (waitPath != null) {if (adapter.getType(dayOfMonthToday).equals(DayType.WAITING)) {if (x >= waitRect.left && y >= waitRect.top && x <= waitRect.right && y <= waitRect.bottom) { if (onTodayClickListener != null) {onTodayClickListener.onTodayClick();}}}}}return true;}public void setAdapter(CalendarAdapter adapter) {this.adapter = adapter;this.invalidate();}public int getDayOfMonthToday() {return dayOfMonthToday;}public void notifyDataSetChanged() {invalidate();}private OnTodayClickListener onTodayClickListener;public void setOnTodayClickListener(OnTodayClickListener onTodayClickListener) {this.onTodayClickListener = onTodayClickListener;}public interface OnTodayClickListener {void onTodayClick();}public enum DayType {/*** 已签到状态,时间已过*/SIGNED(0),/*** 未签到状态,时间已过*/UNSIGNED(1),/*** 等待状态,即当⽇还未签到*/WAITING(2),/*** 不可达到状态,未到时间*/UNREACHABLE(3),/*** 不可⽤状态,⾮当前⽉份*/DISABLED(4);private int value;DayType(int value) {this.value = value;}public int getValue() {return value;}public static DayType valueOf(int value) {switch (value) {case 0:return SIGNED;case 1:return UNSIGNED;case 2:return WAITING;case 3:return UNREACHABLE;case 4:return DISABLED;default:return DISABLED;}}}}以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

Android自定义View实现绘制虚线的方法详解

Android自定义View实现绘制虚线的方法详解

Android⾃定义View实现绘制虚线的⽅法详解前⾔说实话当第⼀次看到这个需求的时候,第⼀反应就是Canvas只有drawLine⽅法,并没有drawDashLine⽅法啊!这咋整啊,难道要我⾃⼰做个遍历不断的drawLine?不到1秒,我就放弃这个想法了,因为太恶⼼了。

⽅法肯定是有的,只不过我不知道⽽已。

绘制⽅法最简单的⽅法是利⽤ShapeDrawable,⽐如说你想⽤虚线要隔开两个控件,就可以在这两个控件中加个View,然后给它个虚线背景。

嗯,理论上就是这样⼦的,实现上也很简单。

<!-- drawable ⽂件 --><?xml version="1.0" encoding="utf-8"?><shape xmlns:android="/apk/res/android"android:shape="line"><strokeandroid:width="1dp"android:color="@color/dash_line"android:dashGap="2dp"android:dashWidth="3dp"/></shape><!-- 布局⽂件 --><?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android"xmlns:tools="/tools"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:gravity="center"tools:context="hope.example.dashlinedemo.MainActivity"><TextViewandroid:layout_width="match_parent"android:layout_height="40dp"android:gravity="center"android:text="分享给微信好友"/><Viewandroid:layout_width="match_parent"android:layout_height="2dp"android:background="@drawable/dash_line" /><TextViewandroid:layout_width="match_parent"android:layout_height="40dp"android:gravity="center"android:text="分享⾄朋友圈" /></LinearLayout>写完之后,从Android Studio的预览功能上就可以看到效果了。

Android 自定义View消除锯齿实现图片旋转,添加边框及文字说明

Android 自定义View消除锯齿实现图片旋转,添加边框及文字说明

先看看图片的效果,左边是原图,右边是旋转之后的图;之所以把这个写出来是因为在一个项目中需要用到这样的效果,我试过用FrameLayout 布局如上的画面,然后旋转FrameLayout,随之而来也就存在了一些问题——锯齿!在网上搜索之后,有两种方法,一是利用Paint,二是利用Canvas;(1)、paint.setAntiAlias(true);paint.setFlags(Paint.ANTI_ALIAS_FLAG);(2)、DrawFilter pfdf = new PaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);canvas.setDrawFilter(pfdf);而如果利用paint,或者canvas,需要从哪获取paint/canvas,这也是一个问题;在实现的过程中,尝试过自定义FrameLayout下面的单个View{ImageView,TextView},但都以失败告终,失败的主要问题在于右图下边的文字描述无法和相片边框相对齐,而且用Matrix旋转背景之后背景大小改变,位置也不在最下边,所以就采用了单独实现一个View的方法,主要原因还是因为自身对Canvas绘图及Paint画笔不是很熟悉,所以导致的效率不高;public class RotateTextImageView extends View {PaintFlagsDrawFilter pfdf;Paint paint;Matrix matrix;Bitmap bitmap;int index = -1;private int oriHeight;private int oriWidth;private int newHeight;private int newWidth;private int angle = 5;protected Path path = new Path();private float[] f = new float[8];private int shawHeight = 20;private int borderSize = 8;Bitmap oriBitmap;private String text = "";public RotateTextImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle);initCanvasInfo();}public RotateTextImageView(Context context, AttributeSet attrs) { super(context, attrs);initCanvasInfo();}public RotateTextImageView(Context context) {super(context);initCanvasInfo();}/*** 初始化Paint*/protected void initCanvasInfo() {pfdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG| Paint.FILTER_BITMAP_FLAG);paint = new Paint();paint.setAntiAlias(true);matrix = new Matrix();matrix.setRotate(5);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);paint.reset();// 消除锯齿paint.setAntiAlias(true);paint.setFlags(Paint.ANTI_ALIAS_FLAG);canvas.setDrawFilter(pfdf);canvas.drawBitmap(bitmap, 0, 0, paint);newHeight = bitmap.getHeight();newWidth = bitmap.getWidth();calculatePoints();// 添加阴影path.reset();path.moveTo(f[0], f[1]);path.lineTo(f[2], f[3]);path.lineTo(f[4], f[5]);path.lineTo(f[6], f[7]);path.close();paint.setStyle(Paint.Style.FILL_AND_STROKE);paint.setColor(Color.parseColor("#96ffffff"));canvas.drawPath(path, paint);// 添加字符if (text != null && !text.equals("")) {path.reset();paint.setTextSize(18);float width = paint.measureText(text);path.moveTo((f[0] + f[2]) / 2, (f[1] + f[3]) / 2);path.lineTo((f[4] + f[6]) / 2, (f[5] + f[7]) / 2);paint.setColor(Color.parseColor("#2b2b2b"));canvas.drawTextOnPath(text, path, (oriWidth - width) / 2, 3, paint);}layout(0, 0, newWidth, newHeight);}/*** 计算坐标值*/private void calculatePoints() {double a = angle * Math.PI / 180;BigDecimal height = new BigDecimal(oriHeight);BigDecimal width = new BigDecimal(oriWidth);BigDecimal cos = new BigDecimal(Math.cos(a));BigDecimal tan = new BigDecimal(Math.tan(a));f[0] = 0;f[1] = height.multiply(cos).floatValue();f[2] = tan.multiply(new BigDecimal(shawHeight)).floatValue();f[3] = (new BigDecimal(f[1])).subtract(new BigDecimal(shawHeight)) .floatValue();f[4] = width.multiply(cos).add(new BigDecimal(f[2])).floatValue();f[5] = new BigDecimal(newHeight - shawHeight).floatValue();f[6] = width.multiply(cos).floatValue();f[7] = new BigDecimal(newHeight).floatValue();}/*** 设置图片** @param bmp*/public void setBitmap(Bitmap bmp) {oriBitmap = bmp;matrix.reset();matrix.setRotate(angle);Bitmap bitmapF = addFrame(bmp);oriHeight = bitmapF.getHeight();oriWidth = bitmapF.getWidth();bitmap = Bitmap.createBitmap(bitmapF, 0, 0, bitmapF.getWidth(),bitmapF.getHeight(), matrix, true);postInvalidate();}/*** 旋转角度** @param angle*/public void setAngle(int angle) {this.angle = angle;setBitmap(oriBitmap);}/*** 设置底部阴影高度** @param shawHeight*/public void setShawHeight(int shawHeight) {this.shawHeight = shawHeight;postInvalidate();}/*** 生成添加了白色边缘的图** @param bmp* @return*/protected Bitmap addFrame(Bitmap bmp) {Bitmap bmpWithBorder = Bitmap.createBitmap(bmp.getWidth() + borderSize* 2, bmp.getHeight() + borderSize * 2, bmp.getConfig());Canvas canvas = new Canvas(bmpWithBorder);canvas.drawColor(Color.WHITE);canvas.drawBitmap(bmp, borderSize, borderSize, null);return bmpWithBorder;}/*** 设置字符串** @param text*/public void setText(String text) {this.text = text;postInvalidate();}/*** 获取字体高度*/protected int getFontHeight() {FontMetrics fm = paint.getFontMetrics();return (int) Math.ceil(fm.descent - fm.top) + 2;}}代码解释:其实没有什么难的东西,只是一些数学运算,代码中每一个方法都有对应的功能注释。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Android高手进阶教程(三)之----Android 中自定义View的应用. 2010-04-18 21:11:25标签:Android进阶View定义教程原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处、作者信息和本声明。

否则将追究法律责任。

/1556324/311457大家好我们今天的教程是在Android 教程中自定义View 的学习,对于初学着来说,他们习惯了Android 传统的页面布局方式,如下代码:view plaincopy to clipboardprint?1.<?xml version="1.0" encoding="utf-8"?>2.<LinearLayout xmlns:android="/apk/res/android"3. android:orientation="vertical"4. android:layout_width="fill_parent"5. android:layout_height="fill_parent"6. >7.<TextView8. android:layout_width="fill_parent"9. android:layout_height="wrap_content"10. android:text="@string/hello"11. />12.</LinearLayout>13.<?xml version="1.0" encoding="utf-8"?>14.<LinearLayout xmlns:android="/apk/res/android"15. android:orientation="vertical"16. android:layout_width="fill_parent"17. android:layout_height="fill_parent"18. >19.<TextView20. android:layout_width="fill_parent"21. android:layout_height="wrap_content"22. android:text="@string/hello"23. />24.</LinearLayout>当然上面的布局方式可以帮助我们完成简单应用的开发了,但是如果你想写一个复杂的应用,这样就有点牵强了,大家不信可以下源码都研究看看,高手写的布局方式,如上面的布局高手通常是这样写的:view plaincopy to clipboardprint?1.<?xml version="1.0" encoding="utf-8"?>2.<A>3. <B></B>4.</A>5.<?xml version="1.0" encoding="utf-8"?>6.<A>7. <B></B>8.</A>view plaincopy to clipboardprint?其中A extends LinerLayout, B extends TextView.其中A extends LinerLayout, B extends TextView.为了帮助大家更容易理解,我写了一个简单的Demo ,具体步骤如下:首先新建一个Android 工程命名为ViewDemo .然后自定义一个View 类,命名为MyView(extends View) .代码如下:1.view plaincopy to clipboardprint?2.package com.android.tutor;3.import android.content.Context;4.import android.graphics.Canvas;5.import android.graphics.Color;6.import android.graphics.Paint;7.import android.graphics.Rect;8.import android.graphics.Paint.Style;9.import android.util.AttributeSet;10.i mport android.view.View;11.p ublic class MyView extends View {12. private Paint mPaint;13. private Context mContext;;15.16. public MyView(Context context) {17. super(context);18.19. }20. public MyView(Context context,AttributeSet attr)21. {22. super(context,attr);23.24. }25. @Override26. protected void onDraw(Canvas canvas) {27. // TODO Auto-generated method stub28. super.onDraw(canvas);29.30. mPaint = new Paint();31.32. //设置画笔颜色33. mPaint.setColor(Color.RED);34. //设置填充35. mPaint.setStyle(Style.FILL);36.37. //画一个矩形,前俩个是矩形左上角坐标,后面俩个是右下角坐标38. canvas.drawRect(new Rect(10, 10, 100, 100), mPaint);39.40. mPaint.setColor(Color.BLUE);41. //绘制文字42. canvas.drawText(mString, 10, 110, mPaint);43. }44.}45.p ackage com.android.tutor;46.i mport android.content.Context;47.i mport android.graphics.Canvas;48.i mport android.graphics.Color;49.i mport android.graphics.Paint;50.i mport android.graphics.Rect;51.i mport android.graphics.Paint.Style;52.i mport android.util.AttributeSet;53.i mport android.view.View;54.p ublic class MyView extends View {55.private Paint mPaint;56.private Context mContext;58.59.public MyView(Context context) {60. super(context);61.62.}63.public MyView(Context context,AttributeSet attr)64.{65. super(context,attr);66.67.}68.@Override69.protected void onDraw(Canvas canvas) {70. // TODO Auto-generated method stub71. super.onDraw(canvas);72.73. mPaint = new Paint();74.75. //设置画笔颜色76. mPaint.setColor(Color.RED);77. //设置填充78. mPaint.setStyle(Style.FILL);79.80. //画一个矩形,前俩个是矩形左上角坐标,后面俩个是右下角坐标81. canvas.drawRect(new Rect(10, 10, 100, 100), mPaint);82.83. mPaint.setColor(Color.BLUE);84. //绘制文字85. canvas.drawText(mString, 10, 110, mPaint);86.}87.}88.89.然后将我们自定义的View 加入到main.xml 布局文件中,代码如下:90.v iew plaincopy to clipboardprint?91.<?xml version="1.0" encoding="utf-8"?>92.<LinearLayout xmlns:android="/apk/res/android"93. android:orientation="vertical"94. android:layout_width="fill_parent"95. android:layout_height="fill_parent"96. >97.<TextView98. android:layout_width="fill_parent"99. android:layout_height="wrap_content"100. android:text="@string/hello"101. />102.<com.android.tutor.MyView103. android:layout_width="fill_parent"104. android:layout_height="fill_parent"105./>106.</LinearLayout>107.<?xml version="1.0" encoding="utf-8"?>108.<LinearLayout xmlns:android="/apk /res/android"109. android:orientation="vertical"110. android:layout_width="fill_parent"111. android:layout_height="fill_parent"112. >113.<TextView114. android:layout_width="fill_parent"115. android:layout_height="wrap_content"116. android:text="@string/hello"117. />118.<com.android.tutor.MyView119. android:layout_width="fill_parent"120. android:layout_height="fill_parent"121./>122.</LinearLayout>最后执行之,效果如下图:OK,大功告成,今天就写到这里,开始做饭了,老婆孩子等我做饭了,lol~对于Android系统的自定义View可能大家都熟悉了,对于自定义View的属性添加,以及Android的Layout的命名空间问题,很多网友还不是很清楚,今天Android123一起再带大家温习一下。

相关文档
最新文档