android自定义布局或View
自定义View
园林美的概念及特征
• 园林美的特征
– 园林中的自然美
• 植物、大自然的山川草木、风云雨雪、日月星辰、虫鱼鸟兽以及大自然晦明、阴晴、晨昏、 昼夜、春秋的瞬息变化、声音美等等。
– 园林中的生活美
• 首先应该使园林的空气清新,无污染,水体清透无异味,卫生条件良好; • 第二,要有宜人的小气候,使气温、湿度、风等综合作用达到理想的要求。 • 第三要避免噪音。要避免噪音的干扰就要在规划时深入研究场地环境,根据具体情况设置防
景
•景
– 是以自然物为主体所形成的,能引起美感的审美 对象,而且必定是以时空为特点(景的最佳观赏 时间、空间)的多维空间,具有诗情画意,令人 赏新悦目,使人流连。
• 园林中的景
– 是指在园林绿地中,自然或经人工创造的,以能 引起人的美感为特征的一种供作游憩观赏的空间 环境。
• 杭州西湖十景(断桥残雪、苏堤春晓、平湖秋月、三 潭映月、柳浪闻莺、雷峰夕照、曲院风荷、双峰插云、 花港观鱼、南屏晚钟)、燕京八景、圆明园四十景、 避暑山庄七十二、连续的、逐渐 的变化。
• 例如自然界中一年四季的季相变化;天穹中自天空到 地平线的色彩变化;人的视野由近到远,物体从清晰 到模糊的过程,建筑墙面由于光源影响所呈现的由明 到暗以及色彩上逐渐的转变等均属之。
图3-4 韵律与节奏
园林构图的基本规律
• 多样与统一
护林或采取消音和隔音的处理。 • 第四植物种类要丰富,生长健壮繁茂,形成立体景观。 • 第五要有方便的交通,完善的生活福利设施,适合园林的文化娱乐活动和美丽安静的休息环
境。
– 园林中的艺术美
桂林山水甲天下
园林构图的基本规律
• 园林绿地构图的含义
– 在一定的空间内,结合各种园林绿地的功能要 求对各种构景要素的取舍、剪裁、配布以及组 合称为园林绿地艺术构图。
View与ViewGroup有什么区别?
View与ViewGroup有什么区别?Android的UI界⾯都是由View和ViewGroup及其派⽣类组合⽽成的。
其中,View是所有UI组件的基类,⽽ ViewGroup是容纳这些组件的容器,其本⾝也是从View派⽣出来的. View对象是Android平台中⽤户界⾯体现的基础单位。
View类是它称为“widgets(⼯具)”的⼦类的基础,它们提供了诸如⽂本输⼊框和按钮之类的UI对象的完整实现。
ViewGroup类同样为其被称为“Layouts(布局)”的⼦类奠定了基础,它们提供了象流式布局、表格布局以及相对布局之类的布局架构。
⼀般来说,开发Android应⽤程序的UI界⾯都不会直接使⽤View和ViewGroup,⽽是使⽤这两⼤基类的派⽣类。
View派⽣出的直接⼦类有:AnalogClock,ImageView,KeyboardView, ProgressBar,SurfaceView, TextView,ViewGroup,ViewStub View派⽣出的间接⼦类有:AbsListView,AbsSeekBar, AbsSpinner, AbsoluteLayout,AdapterView,AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView,AutoCompleteTextView,Button,CalendarView, CheckBox, CheckedTextView, Chronometer, CompoundButton, ViewGroup派⽣出的直接⼦类有:AbsoluteLayout,AdapterView,FragmentBreadCrumbs,FrameLayout, LinearLayout,RelativeLayout,SlidingDrawer ViewGroup派⽣出的间接⼦类有:AbsListView,AbsSpinner, AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, CalendarView, DatePicker, DialerFilter, ExpandableListView, Gallery, GestureOverlayView,GridView,HorizontalScrollView, ImageSwitcher,ListView, 这⾥特别指出,ImageView是布局具有图⽚效果的UI常⽤的类,SurfaceView是⽤来进⾏游戏开发的与⼀般View 相⽐较为特殊的⾮常重要的类,⽽AbsoluteLayout、 FrameLayout,LinearLayout, RelativeLayout这⼏个ViewGroup 的直接⼦类是Android UI布局中最基本的布局元素。
Android自定义View控件实现刷新效果
Android⾃定义View控件实现刷新效果三种得到LinearInflater的⽅法a. LayoutInflater inflater = getLayoutInflater();b. LayoutInflater localinflater =(LayoutInflater)context.getSystemService(YOUT_INFLATER_SERVICE);c. LayoutInflater inflater = LayoutInflater.from(context);onDraw ⽅法绘图,invalidate刷新界⾯。
效果图:点击⼀下换颜⾊onDraw画完图后,给控件设置点击事件 ,将参数传到控件⾥,然后invalidate刷新1.onDraw画图,并增加changeColor⽅法public class CusView3 extends View {private int color = 0;public CusView3(Context context, AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);Paint mPaint = new Paint();if (color > 2) {color = 0;}switch (color) {case 0:mPaint.setColor(Color.GREEN);break;case 1:mPaint.setColor(Color.RED);break;case 2:mPaint.setColor(Color.BLUE);break;default:break;}mPaint.setStyle(Style.FILL);mPaint.setTextSize(35.0f);canvas.drawText("点击我刷新", 10, 60, mPaint);}public void changeColor() { //为了让外⾯调⽤color++;}}2.布局<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><xue.test.CusView3android:id="@+id/cusview3"android:layout_width="wrap_content"android:layout_height="wrap_content"></xue.test.CusView3></LinearLayout>3.画图后给控件设置点击事件 ,将参数传到控件⾥,然后invalidate刷新public class TestCustomViewActivity extends Activity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.main);view3 = (CusView3) findViewById(R.id.cusview3);// 点击事件view3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Message message = new Message();message.what = 1;myHandler.sendMessage(message);}});}Handler myHandler = new Handler() {// 接收到消息后处理public void handleMessage(Message msg) {switch (msg.what) {case 1:// 调⽤⽅法view3.changeColor();// 刷新⽅法view3.invalidate();break;}super.handleMessage(msg);}};private CusView3 view3;}⾄于⾃定义控件占整屏的问题,可能需要⽤layoutparams以上所述是⼩编给⼤家介绍的Android⾃定义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>这个布局很简单,就不多说了。
为什么你的自定义View wrap_content不起作用?
为什么你的自定义View wrap_content不起作用?前言自定义View是Android开发中非常常用的知识可是,在使用过程中,有些开发者会发现:为什么自定义View 中设置的wrap_content属性不起作用(与match_parent相同作用)?今天,我将全面分析上述问题并给出解决方案。
1. 问题描述在使用自定义View时,View宽/ 高的wrap_content属性不起自身应有的作用,而且是起到与match_parent相同作用。
wrap_content与match_parent区别:1. wrap_content:视图的宽/高被设定成刚好适应视图内容的最小尺寸2. match_parent:视图的宽/高被设置为充满整个父布局(在Android API 8之前叫作fill_parent)其实这里有两个问题:问题1:wrap_content属性不起自身应有的作用问题2:wrap_content起到与match_parent相同的作用问题分析问题出现在View的宽/ 高设置,那我们直接来看自定义View绘制中第一步对View宽/ 高设置的过程:measure过程中的onMeasure()方法onMeasure()protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//参数说明:View的宽/ 高测量规格//setMeasuredDimension() 用于获得View宽/高的测量值//这两个参数是通过getDefaultSize()获得的setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}继续往下看getDefaultSize()getDefaultSize()作用:根据View宽/高的测量规格计算View的宽/高值源码分析如下:public static int getDefaultSize(int size, int measureSpec) {//参数说明:// 第一个参数size:提供的默认大小// 第二个参数:宽/高的测量规格(含模式& 测量大小)//设置默认大小int result = size;//获取宽/高测量规格的模式& 测量大小int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);switch (specMode) {// 模式为UNSPECIFIED时,使用提供的默认大小// 即第一个参数:sizecase MeasureSpec.UNSPECIFIED:result = size;break;// 模式为AT_MOST,EXACTL Y时,使用View测量后的宽/高值// 即measureSpec中的specSizecase MeasureSpec.AT_MOST:case MeasureSpec.EXACTL Y:result = specSize;break;}//返回View的宽/高值return result;}从上面发现:在getDefaultSize()的默认实现中,当View的测量模式是AT_MOST或EXACTL Y时,View 的大小都会被设置成子View MeasureSpec的specSize。
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;//如果不加这⼀⾏的条件,出来之后是完整单词+。
安卓手机页面设置方法
安卓手机页面设置方法在安卓手机上,页面设置是指调整屏幕显示的内容和布局,以便更好地适应用户的需求和喜好。
以下是一些常见的安卓手机页面设置方法。
一、壁纸设置1. 找到手机的“设置”应用,一般在应用列表中或者在快捷设置菜单中。
2. 在“设置”中找到“壁纸”选项。
3. 点击“壁纸”,选择“主屏幕”或者“锁定屏幕”。
4. 在壁纸库中选择您喜欢的图片或者从相册中选择图片。
5. 调整壁纸的位置和缩放方式,然后保存设置即可。
二、字体大小调整1. 找到手机的“设置”应用。
2. 在“设置”中找到“显示”或者“屏幕显示”选项。
3. 点击“显示”或者“屏幕显示”,找到“字体大小”选项。
4. 在字体大小选项中,选择适合您的字体大小,或者点击“自定义”调整字体大小。
5. 保存设置并退出。
三、图标布局调整1. 长按主屏幕上的空白区域,进入主屏幕设置界面。
2. 点击“桌面布局”或者“图标布局”选项。
3. 在布局选项中,选择您想要的图标尺寸和行列数。
4. 拖动图标到新的位置,或者删除不需要的图标。
5. 保存设置并退出。
四、通知栏和快捷设置定制1. 下拉通知栏,并点击右上角的“设置”图标。
2. 在设置菜单中,找到“通知和状态栏”或者“快捷设置”选项。
3. 点击“通知和状态栏”或者“快捷设置”,进入设置界面。
4. 可以根据需要进行以下操作:- 调整通知栏样式:选择是否显示通知图标和通知内容等。
- 设置快捷开关:选择要显示的快捷开关,并调整排序和显示方式。
- 隐藏特定通知:选择哪些应用的通知显示在通知栏上。
- 调整状态栏图标:可以隐藏或显示特定的状态栏图标。
- 其他定制选项:可以根据需要设置铃声、震动等通知方式。
5. 保存设置并退出。
五、屏幕显示分辨率调整1. 找到手机的“设置”应用。
2. 在“设置”中找到“显示”或者“屏幕显示”选项。
3. 点击“显示”或者“屏幕显示”,找到“分辨率”选项。
4. 在分辨率选项中,选择您想要的屏幕分辨率。
自定义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的用法有: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的意义
零、序一、自定义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中。
AndroidTablayout自定义Tab布局的使用案例
AndroidTablayout⾃定义Tab布局的使⽤案例开发公司的项⽬中需要实现以下效果图,需要⾃定义TabLayout 中的TabTablayout xml<android.support.design.widget.TabLayoutandroid:id="@+id/dialog_mod_icon_tablayout"android:layout_width="wrap_content"android:layout_height="wrap_content"app:tabIndicatorHeight="0dp"android:paddingLeft="@dimen/commom_margin_20"app:tabMode="scrollable"app:tabPaddingStart="@dimen/commom_margin_5"app:tabPaddingEnd="@dimen/commom_margin_5"app:tabSelectedTextColor="@color/common_tv_dark_red" />其中如果多个tab 需要滚动则要设置app:tabMode="scrollable",对于tabPaddingStart与tabPaddingEnd则是设置Tab 的左边和右边padding,根据具体的需求来设置就好,这⾥如果没有设置,TabLayout 或⾃动设置⼀个默认的值給Tab,setCustomView()设置⾃定义的Tab布局給TablayoutTabLayout.Tab tab = tabLayout.newTab();View view = LayoutInflater.from(context).inflate(yout.widget_choose_icon_tab_bg, null);TextView tv = (TextView) view.findViewById(R.id.choose_icon_tab_tv);tv.setText(listData.get(i).getName());tab.setCustomView(view);tabLayout.addTab(tab);widget_choose_icon_tab_bg.xml<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/choose_icon_tab_tv"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="center"android:background="@drawable/selector_icon_choose_txt_bg"android:padding="@dimen/commom_margin_4"android:textSize="@dimen/commom_tv_size_12"android:textStyle="bold" /></LinearLayout>selector_icon_choose_txt_bg<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="/apk/res/android"><item android:drawable="@drawable/shape_icon_choose_select" android:state_checked="true" /><item android:drawable="@drawable/shape_icon_choose_select" android:state_selected="true" /><item android:drawable="@drawable/shape_icon_choose_no_select" /></selector>shape_icon_choose_select<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="/apk/res/android"><corners android:radius="@dimen/commom_margin_2"/><stroke android:color="@color/common_bg_dali_gray_cc4" android:width="1dp"/></shape>shape_icon_choose_no_select<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="/apk/res/android"><corners android:radius="@dimen/commom_margin_2"/><stroke android:color="@color/common_bg_dali_gray_62" android:width="1dp"/></shape>通过以上设置,就实现了我图中TabLayout 的⼦Tab的布局。
Android布局——Preference自定义layout的方法
Android布局——Preference⾃定义layout的⽅法导语:PreferenceActivity是⼀个⽅便设置管理的界⾯,但是对于界⾯显⽰来说⽐较单调,所以⾃定义布局就很有必要了。
本⽂举例说明在Preference中⾃定义layout的⽅法。
笔者是为了在设置中插⼊@有⽶v4⼴告条才研究了⼀晚上的。
正⽂:⾸先PreferenceScreen是⼀个xml⽂件于res/xml⽬录下,不属于layout⽂件。
要插⼊layout,有两种⽅法。
1.使⽤Preference的android:@layout属性1)xml⽂件中preference的添加复制代码代码如下:<Preference android:layout="@layout/youmi_ad" android:key="youmi_ad"/>2)layout.xml复制代码代码如下:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="wrap_content"><!-- 有⽶⼴告 --><akai.settings.YoumiAdandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:gravity="center_horizontal"/></LinearLayout>3)由于v4版本的⼴告条需要⾃⼰定义layout载体,所以这⾥重载了⼀个LinearLayout,⾃定义布局也是如此。
Android系统常用布局介绍
Android系统常用布局介绍Android中的布局包括线性布局,表格布局,相对布局,帧布局,绝对布局。
下面分别对每个布局进行一个介绍。
在介绍android的布局管理器之前,有必要了解android平台下的控件类。
首先要了解的是View类,该类为所有可视化控件的基类,主要提供了控件绘制和事件处理的方法。
创建用户界面所使用的控件都继承自View,如TextView,Button,CheckBox等。
补充:另外一个需要了解的是ViewGroup类,它也是View类的子类,但是可以充当其他控件的容器。
ViewGroup的子控件既可以是普通的View,也可以是ViewGroup。
Android中的一些高级控件如Gally,GirdView等都继承自ViewGroup。
一:线性布局:LinearLayout类简介线性布局是最简单的布局之一,它提供了控件水平或者垂直排列的模型。
同时,使用此布局时可以通过设置控件的weight参数控制各个控件在容器中的相对大小。
LinearLayout布局的属性既可以在布局文件(XML)中设置,也可以通过成员方法进行设置。
案例:1.在布局管理器中实现布局:在eclipse中新建一个项目。
首先打开项目文件夹下res/values目录下的string.xml,写入一下内容:<?xml version=”1.0”encoding=”utf-8”?><resources><string name=”app_name”>LinearExample</string><string name=”button”>按钮</string><string name=”add”>添加</string></resources>说明:在string.xml中主要声明了程序中要用到的字符串资源,这样将所有字符串资源统一管理有助于提高程序的可读性及可维护性。
自定义view的绘制流程
自定义view的绘制流程自定义View的绘制流程。
在Android开发中,自定义View是非常常见的需求,通过自定义View可以实现各种炫酷的效果,满足各种个性化的设计需求。
但是,自定义View的绘制流程并不是那么简单,需要我们对View的绘制机制有一定的了解,才能够高效地实现自定义View的绘制。
本文将从自定义View的基本概念开始,逐步介绍自定义View的绘制流程。
1. 自定义View的基本概念。
自定义View是指在Android开发中,通过继承View或者ViewGroup来创建自定义的UI控件。
通过自定义View,我们可以实现各种各样的UI效果,比如自定义的按钮样式、进度条样式、图表样式等。
自定义View的核心就是重写View或者ViewGroup的绘制方法,以实现我们所需的UI效果。
2. 自定义View的绘制流程。
自定义View的绘制流程可以分为以下几个步骤:(1)onMeasure,测量View的大小。
在onMeasure方法中,我们需要通过调用setMeasuredDimension方法来设置View的大小。
在这个方法中,我们需要考虑View的宽度和高度,以及View的测量模式。
通常情况下,我们需要根据View的内容和父容器的大小来计算View的大小,并根据测量模式来确定View的最终大小。
(2)onLayout,确定View的位置。
在onLayout方法中,我们需要通过调用layout方法来确定View在父容器中的位置。
在这个方法中,我们需要考虑View的左上右下四个位置,以及父容器的大小和布局方式,来确定View的最终位置。
(3)onDraw,绘制View的内容。
在onDraw方法中,我们需要通过Canvas来绘制View的内容。
在这个方法中,我们可以使用各种绘制方法来绘制文字、图形、图片等内容,以实现我们所需的UI效果。
在绘制过程中,我们还可以通过Paint来设置绘制的样式、颜色、字体等属性,以实现更加丰富的UI效果。
如何使用Android Studio进行布局设计和界面编写
使用Android Studio进行布局设计和界面编写随着移动应用的快速发展,Android平台成为开发人员的首选之一。
而在Android开发中,布局设计和界面编写则是开发过程中的重要环节。
本文将介绍如何使用Android Studio进行布局设计和界面编写,帮助初学者顺利入门。
一、概述在开始之前,我们先了解一下Android Studio。
Android Studio是谷歌发布的官方集成开发环境(IDE),用于开发Android应用程序。
它提供了丰富的工具和功能,便于开发者进行布局设计和界面编写。
二、安装和配置首先,你需要从官方网站或官方应用商店下载并安装Android Studio。
安装完成后,打开Android Studio,并按照提示进行相关配置,例如选择Android SDK的路径和配置虚拟设备等。
三、布局设计1. 创建新项目在Android Studio中,点击"Start a new Android Studio project",然后按照向导进行项目创建。
在创建项目时,你可以选择项目类型、包名、存储位置等。
2. 层次结构当项目创建完成后,你会看到一个名为"res"的目录,它包含了应用程序的资源文件。
其中,"layout"目录是布局文件所在的位置。
你可以在此目录下创建XML文件,用于定义应用程序的布局。
3. 使用布局编辑器在"layout"目录中,右键点击并选择"New -> Layout Resource File",然后填写文件名并选择布局类型。
接下来,你将进入布局编辑器界面。
在布局编辑器中,你可以通过拖拽组件或手动编写XML代码来设计界面布局。
四、界面编写1. XML布局文件在布局设计阶段,你已经创建了XML布局文件。
现在,你需要在Java代码中引用这些布局文件,并设置相应的逻辑。
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实现绘制虚线的⽅法详解前⾔说实话当第⼀次看到这个需求的时候,第⼀反应就是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布局居中的几种做法
Android布局居中的⼏种做法Android的布局⽂件中,如果想让⼀个组件(布局或View)居中显⽰在另⼀个布局(组件)中,可以由这么⼏种做法:1. android:layout_gravity2. android:gravity3. android:layout_centerInParentlayout_gravityandroid:layout_gravity ,⽤来指定当前组件(布局或View)在⽗组件(布局)中的位置,⽗布局应该是LinearLayout或者它的后裔。
layout_gravity取值可能是:1. top2. bottom3. left4. right5. center_vertical6. fill_vertical7. center_horizontal8. fill_horizontal9. center10. fill11. clip_vertical12. clip_horizontal13. start14. end与居中相关的已经粗体标注出来。
各种取值的具体含义,参看:gravity与居中相关的取值:1. center2. center_horizontal3. center_vertical当你设定⼀个布局 android:gravity="center" 时,它的⼦组件就会居中。
当你设定⼀个View android:gravity="center" 时,它的内容会居中,以TextView为例,⽂字会居中。
layout_centerInParentandroid:layout_centerInParent 是RelativeLayout的布局属性,如果⼀个组件(布局或View)的⽗布局是RelativeLayout,就可以使⽤这个属性来居中。
其取值为 true 或 false 。
与其类似的还有:1. android:layout_centerHorizontal2. android:layout_centerVertical以上就是对Android 布局居中的⼏种⽅法整理,后续继续补充相关资料,谢谢⼤家对本站的⽀持!。
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;}}代码解释:其实没有什么难的东西,只是一些数学运算,代码中每一个方法都有对应的功能注释。
深入解析Android的自定义布局
深入解析Android的自定义布局写在前面的话:这篇文章是前Firefox Android工程师(现在跳槽去Facebook了) Lucas Rocha所写,文中对Android中常用的四种自定义布局方案进行了很好地分析,并结合这四种Android 自定义布局方案所写的示例项目讲解了它们各自的优劣以及四种方案之间的比较。
看完这篇文章,也让我对Android 自定义布局有了进一步的了解,于是趁着兴头,我把它翻译成中文,原文链接在此。
只要你写过Android程序,你肯定使用过Android平台内建的几个布局——RelativeLayout, LinearLayout, FrameLayout等等。
它们能帮助我们很好的构建Android UI。
这些内建的布局已经提供了很多方便的构件,但很多情况下你还是需要来定制自己的布局。
总结起来,自定义布局有两大优点:1. 通过减少view的使用和更快地遍历布局元素让你的UI显示更加有效率;2. 可以构建那些无法由已有的view实现的UI。
在这篇博文中,我将实现四种不同的自定义布局,并对它们的优缺点进行比较。
它们分别是: composite view , custom composite view , flat custom view , 和 async custom views 。
这些代码实现可以在我的github上的 android-layout-samples 项目里找到。
这个app 使用上面说到的四种自定义布局实现了相同的UI效果。
它们使用 Picasso 来加载图片。
这个app的UI只是twitter timeline的简化版本——没有交互,只有布局。
好啦,我们先从最常见的自定义布局开始吧: composite view。
Composite ViewComposite views (也被称为 compound views) 是众多将多个view结合成为一个可重用UI组件的方法中最简单的。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
自定义Dialog;
dialog = new Dialog(this);
dialog.setContentView(yout.by_baseinfo);
dialog.setTitle("dialog的title");
/*
* 获取Dialog的窗口对象及参数对象以修改对话框的布局设置, 可以直接调用this.getWindow(),表示获得这个Activity的Window
* 对象,这样这可以以同样的方式改变这个Activity的属性.
* Activity不可见时getWindow()返回值为null;
*/
Window dialogWindow = dialog.getWindow();
// 对话框的布局设置参数;
youtParams layoutParams = dialogWindow.getAttributes();
// 设置Window中的内容为左上对齐;
dialogWindow.setGravity(Gravity.LEFT | Gravity.TOP);
/*
* lp.x与lp.y表示相对于原始位置的偏移.
* 当参数值包含Gravity.LEFT时,对话框出现在左边,所以lp.x就表示相对左边的偏移,负值忽略.
* 当参数值包含Gravity.RIGHT时,对话框出现在右边,所以lp.x就表示相对右边的偏移,负值忽略.
* 当参数值包含Gravity.TOP时,对话框出现在上边,所以lp.y就表示相对上边的偏移,负值忽略.
* 当参数值包含Gravity.BOTTOM时,对话框出现在下边,所以lp.y就表示相对下边的偏移,负值忽略.
* 当参数值包含Gravity.CENTER_HORIZONTAL时
* ,对话框水平居中,所以lp.x就表示在水平居中的位置移动lp.x像素,正值向右移动,负值向左移动.
* 当参数值包含Gravity.CENTER_VERTICAL时
* ,对话框垂直居中,所以lp.y就表示在垂直居中的位置移动lp.y像素,正值向右移动,负值向左移动.
* gravity的默认值为Gravity.CENTER,即Gravity.CENTER_HORIZONTAL |
* Gravity.CENTER_VERTICAL.
*
* 本来setGravity的参数值为Gravity.LEFT | Gravity.TOP时对话框应出现在程序的左上角,但在
* 我手机上测试时发现距左边与上边都有一小段距离,而且垂直坐标把程序标题栏也计算在内了, Gravity.LEFT, Gravity.TOP,
* Gravity.BOTTOM与Gravity.RIGHT都是如此,据边界有一小段距离
*/
// 相对于屏幕原位置(加上标题栏) 的偏移量;
lp.x = 100; // 新位置X坐标
lp.y = 100; // 新位置Y坐标
lp.width = 300; // 宽度
lp.height = 300; // 高度
lp.alpha = 0.7f; // 透明度
/*
* 将对话框的大小按屏幕大小的百分比设置
*/
Display display = this.getWindowManager().getDefaultDisplay();
youtParams layoutParams = this.getWindow()
.getAttributes();
将对话框的大小按屏幕大小的百分比设置
layoutParams.width = (int) (display.getWidth() * 0.6);
layoutParams.height = (int) (display.getHeight() * 0.6);
dialogWindow.setAttributes(layoutParams); // 设置该属性后Dialog 窗口的宽度;
android Dialog去掉标题栏和边框
<!--重写系统弹出Dialog -->
<style name="myDialogTheme" parent="android:Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item><!--除去title-->
<item name="android:windowContentOverlay">@null</item>
<item name="android:backgroundDimEnabled">false</item>
<item name="android:windowBackground">@null</item><!--除去背景色--></style>
如果是用于Activity;在你注册activity中加入android:theme="@style/myDialogTheme" 这个名就是上面的样式名称;
窗口都是有Window的;比如Activity,Dialog;
可以通过getWindow()方法获得Window对象;
Android自定义View之一:初探实例
继承View,重写构造函数、onDraw,(onMeasure)等函数。
如果自定义的View需要有自定义的属性,需要在values下建立attrs.xml。
在其中定义你的属性。
在使用到自定义View的xml布局文件中需要加入xmlns:前缀="/apk/res/你的自定义View所在的包路径".
在使用自定义属性的时候,使用前缀:属性名,如my:textColor="#FFFFFFF"。
Attrs.xml一般存放我们自定义控件的一些属性;在attrs.xml文件中定义属性的类型,即字符串还是数值
Android自定义组件之TextView
自定义TextView组件,让它既能显示文本,又能显示图像,达到“图文并茂”的效果。
这种情景在新闻、文章、彩信内容中很常见。
1.创建attrs.xml文件用于设置自定义组件的属性、类型和样式。
2.利用android.content.res.TypedArray类将自定义组件装载到程序,以供程序调用。
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.customTextView);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.customTextView);3.布局文件引入自定义组件需要如下设置
自定义组件命名空间:
[html]
xmlns:custom="/apk/res/com.custom.textview"。