前言
此篇博客简略介绍android sdk自带的一些特别好用但是常常忘记的组件。常用的TextView、Button、ImageView和几个常用布局就不介绍了
标题栏组件
<androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="0dp" android:layout_height="wrap_content" android:background="@color/colorPrimary" app:title="@string/forget_password"//标题文字 app:titleTextAppearance="@style/TitleText"//设置标题文字风格 app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"> </androidx.appcompat.widget.Toolbar>
<style name="TitleText" parent="TextAppearance.Widget.AppCompat.Toolbar.Title"> <item name="android:color">@color/colorWhite</item> <item name="android:textSize">20dp</item> </style>
滚动组件
<ScrollView android:layout_width="wrap_content" android:layout_height="wrap_content"></ScrollView>
横向滚动组件
注意点:
1.滚动布局下,只能包含一个子布局,但是子布局下面可以包含多个布局。
<HorizontalScrollView android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageView android:layout_width="200dp" android:layout_height="200dp" android:background="#ff00ff" /> <ImageView android:layout_width="200dp" android:layout_height="200dp" android:background="#000000" /> <ImageView android:layout_width="200dp" android:layout_height="200dp" android:background="#b7a500" /> </LinearLayout> </HorizontalScrollView>
网格列表组件
<GridView android:id="@+id/gridview" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:horizontalSpacing="1dp" android:numColumns="3" android:verticalSpacing="1dp"> </GridView>
常用的属性:
android:numColumns="auto_fit" ,GridView的列数设置为自动
android:columnWidth="90dp",每列的宽度,也就是Item的宽度
android:stretchMode="columnWidth",缩放与列宽大小同步
android:verticalSpacing="10dp",两行之间的边距
android:horizontalSpacing="10dp",两列之间的边距
例子1 使用ArrayAdapter:
List<String> stringList = new ArrayList<>(); ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(this,R.layout.text_parent_select_item,stringList); gridView.setAdapter(arrayAdapter);
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/name" android:layout_width="75dp" android:layout_height="37dp" android:textSize="@dimen/font_size_16" android:textColor="@color/fontBlack1" android:gravity="center" android:maxLines="1" android:background="@drawable/bg_orange_edge_rectangle"> </TextView>
例子2 使用SimpleAdapter:
Activity类
public class MainActivity extends Activity { private GridView gridView; private List<Map<String, Object>> dataList; private SimpleAdapter adapter; //如果只有TextView 可以考虑使用ArrayAdapter 适配器,当然你也可以自定义适配器 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); gridView = (GridView) findViewById(R.id.gridview); //初始化数据 initData(); String[] from={"img","text"}; int[] to={R.id.img,R.id.text}; adapter=new SimpleAdapter(this, dataList, R.layout.gridview_item, from, to); gridView.setAdapter(adapter); gridView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { AlertDialog.Builder builder= new AlertDialog.Builder(MainActivity.this); builder.setTitle("提示").setMessage(dataList.get(arg2).get("text").toString()).create().show(); } }); } void initData() { //图标 int icno[] = { R.drawable.i1, R.drawable.i2, R.drawable.i3, R.drawable.i4, R.drawable.i5, R.drawable.i6, R.drawable.i7, R.drawable.i8, R.drawable.i9, R.drawable.i10, R.drawable.i11, R.drawable.i12 }; //图标下的文字 String name[]={"时钟","信号","宝箱","秒钟","大象","FF","记事本","书签","印象","商店","主题","迅雷"}; dataList = new ArrayList<Map<String, Object>>(); for (int i = 0; i <icno.length; i++) { Map<String, Object> map=new HashMap<String, Object>(); map.put("img", icno[i]); map.put("text",name[i]); dataList.add(map); } } }
GridView主布局文件activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000" tools:context="com.example.l7.MainActivity" > <GridView android:id="@+id/gridview" android:layout_width="match_parent" android:layout_height="wrap_content" android:columnWidth="80dp" android:stretchMode="spacingWidthUniform" android:numColumns="3" /> </LinearLayout>
列表项布局gridview_item.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="vertical" > <ImageView android:id="@+id/img" android:layout_width="60dp" android:layout_height="60dp" android:layout_marginTop="10dp" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="2dp" android:layout_gravity="center" android:textColor="#FFF" android:text="文字" /> </LinearLayout>
格外注意!如果你是滚动布局(ListView、ScrollView等等)包裹GridView,就出现不会自动换行的问题。这个时候需要你如下自定义view。
package com.weijie.app_user.activity.order; import android.content.Context; import android.util.AttributeSet; import android.widget.GridView; public class MyGridView extends GridView { public MyGridView(Context context, AttributeSet attrs) { super(context, attrs); } public MyGridView(Context context) { super(context); } public MyGridView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec( Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } }
网格布局
本身属性
- android:alignmentMode
- 说明:当设置alignMargins,使视图的外边界之间进行校准。可以取以下值:
- alignBounds – 对齐子视图边界。
- alignMargins – 对齐子视距内容。
- android:columnCount
- 说明:GridLayout的最大列数
- android:rowCount
- 说明:GridLayout的最大行数
- android:columnOrderPreserved
- 说明:当设置为true,使列边界显示的顺序和列索引的顺序相同。默认是true。
- android:orientation
- 说明:GridLayout中子元素的布局方向。有以下取值:
- horizontal – 水平布局。
- vertical – 竖直布局。
- android:rowOrderPreserved
- 说明:当设置为true,使行边界显示的顺序和行索引的顺序相同。默认是true。
- android:useDefaultMargins
- 说明: 当设置ture,当没有指定视图的布局参数时,告诉GridLayout使用默认的边距。默认值是false。
- android:layout_column
说明:显示该子控件的列,例如android:layout_column=”0”,表示当前子控件显示在第1列,android:layout_column=”1”,表示当前子控件显示在第2列。 -
android:layout_columnSpan
说明:该控件所占的列数,例如android:layout_columnSpan=”2”,表示当前子控件占两列。 -
android:layout_row
说明:显示该子控件的行,例如android:layout_row=”0”,表示当前子控件显示在第1行,android:layout_row=”1”,表示当前子控件显示在第2行。 -
android:layout_rowSpan
说明:该控件所占的列数,例如android:layout_rowSpan=”2”,表示当前子控件占两行。 -
android:layout_columnWeight
说明:该控件的列权重,与android:layout_weight类似,例如有GridLayout上两列,都设置android:layout_columnWeight = “1”,则两列各占GridLayout宽度的一半 - android:layout_rowWeight
说明:该控件的行权重,原理同android:layout_columnWeight。
<GridLayout android:layout_width="match_parent" android:layout_height="match_parent"></GridLayout>
表格布局
适合在桌面这种需要显示多个图标功能的情况下使用,所以别用ListView套GridView了,会麻烦死的。
<TableRow></TableRow> 为列表行
<TableLayout android:layout_width="wrap_content" android:layout_height="wrap_content"></TableLayout>
<?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TableRow > <Button android:id="@+id/button01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮1" ></Button> <Button android:id="@+id/button02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮2" ></Button> <Button android:id="@+id/button03" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮3" ></Button> </TableRow> <TableRow > <Button android:id="@+id/button04" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮4" ></Button> <Button android:id="@+id/button05" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮5" ></Button> <Button android:id="@+id/button06" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮6" ></Button> </TableRow> <TableRow > <Button android:id="@+id/button07" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮7" ></Button> <Button android:id="@+id/button08" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮8" ></Button> <Button android:id="@+id/button09" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮9" ></Button> </TableRow> </TableLayout>
多媒体控制器组件
有快进,快退,进度条
<MediaController android:layout_width="match_parent" android:layout_height="match_parent"></MediaController>
标签栏组件
<TabHost android:layout_width="wrap_content" android:layout_height="wrap_content"></TabHost>
选项卡组件(配合标题栏组件一起使用)
<TabWidget android:layout_width="wrap_content" android:layout_height="wrap_content"></TabWidget>
TabLayout页面切换布局
<com.google.android.material.tabs.TabLayout android:id="@+id/table" android:layout_width="match_parent" android:layout_height="wrap_content"> <com.google.android.material.tabs.TabItem android:id="@+id/into" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="到校"/> <com.google.android.material.tabs.TabItem android:id="@+id/out" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="离校"/>
//常用的属性
app:tabIndicatorColor :指示线的颜色 app:tabIndicatorHeight :指示线的高度 app:tabSelectedTextColor : tab选中时的字体颜色
app:tabTextColor="@color/colorPrimary" :未选中字体颜色
app:tabBackground="color" :整个tablayout颜色 app:tabMode="scrollable" : 默认是fixed,固定的;scrollable:可滚动的
也可以在代码上添加子项
tabLayout.addTab(tabLayout.newTab());
用Tablayout属性写一个style,给需要的Tablayout引用:
<style name="MyTablayoutstyle" parent="Base.Widget.Design.TabLayout"> <item name="tabBackground">@color/white</item> <item name="tabIndicatorColor">@color/green</item> <item name="tabIndicatorHeight">2dp</item> <item name="tabSelectedTextColor">@color/green</item> <item name="android:textSize">15sp</item> <item name="android:textColor">@color/text</item> </style>
Tablayout引用:
<android.support.design.widget.TabLayout android:id="@+id/tab1" style="@style/MyTablayoutstyle" android:layout_width="match_parent" android:layout_height="wrap_content"/>
去掉指示线:
给tabIndicatorHeight属性设置0dp,或者给tabSelectedTextColor属性设置透明,就不显示指示线了
tabLayout.getTabAt(i).setText(titles[i]).setIcon(pics[i]);
添加自定义布局:
tabLayout2.getTabAt(i).setCustomView(makeTabView(i));
按键监听:
tabLayout.setOnTabSelectedListener(newTabLayout.OnTabSelectedListener() { @Override public voidonTabSelected(TabLayout.Tab tab) { //选中了tab的逻辑 } @Override public voidonTabUnselected(TabLayout.Tab tab) { //未选中tab的逻辑 } @Override public voidonTabReselected(TabLayout.Tab tab) { //再次选中tab的逻辑 } });
Spinner下拉列表选择框组件
<Spinner android:layout_width="match_parent" android:layout_height="wrap_content" android:entries="@array/books" android:popupBackground="#66ccff" android:dropDownWidth="230dp"></Spinner>
public class MainActivity extends AppCompatActivity { Spinner spinner; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获取界面布局文件的Spinner组件 spinner= (Spinner) findViewById(R.id.spinner); String[] arr={"孙悟空","猪八戒","唐僧"}; //创建ArrayAdapter对象 ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_multiple_choice,arr); spinner.setAdapter(adapter); String spinnerContent =(String)spinner.getSelectedItem();//获取选中的内容 spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { //选中回调 } @Override public void onNothingSelected(AdapterView<?> parent) { //未选中回调 } }); } }
列表内容下拉扩展组件
其实就是 ListView 加上 下拉列表框 功能的二合一
<ExpandableListView android:id="@+id/ev_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorWhite" android:divider="@null" android:groupIndicator="@null" android:cacheColorHint="#00000000" android:listSelector="#00000000" />
快速关联联系人组件(快速添加到联系人或者获取信息)
<QuickContactBadge android:id="@+id/badge" android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="@drawable/zgdx"/>
图片按钮组件
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_phone_book"/>
文本切换组件(支持有动画切换)
文字也要有切换动画才够酷炫!
<TextSwitcher android:layout_width="wrap_content" android:layout_height="wrap_content"></TextSwitcher>
图片切换组件(支持有动画切换)
有动画切换图片了,肯定更加酷炫
<ImageSwitcher android:layout_width="match_parent" android:layout_height="match_parent"></ImageSwitcher>
视频切换组件(支持有动画切换)
是的,三兄弟到齐了,为了切换动画!
<ViewSwitcher android:layout_width="wrap_content" android:layout_height="wrap_content"></ViewSwitcher>
图片轮播组件
你天天逛的淘宝,上面的让你心动的物品图片轮播,就是这种效果
AdapterViewAnimator支持的XML属性如下:
-
android:animateFirstView:设置显示组件的第一个View时是否使用动画。
-
android:inAnimation:设置组件显示时使用的动画。
-
android:loopViews:设置循环到最后一个组件时是否自动跳转到第一个组件。
-
android:outAnimation:设置组件隐藏时使用的动画。
-
<AdapterViewFlipper android:layout_width="wrap_content" android:layout_height="wrap_content"></AdapterViewFlipper>
Switch滑动按钮组件
一键双状态,但是是滑动开关图标的样子
<!--滑动按钮--> <Switch android:layout_width="wrap_content" android:layout_height="wrap_content"/>
textOn:控件打开时显示的文字
textOff:控件关闭时显示的文字
thumb:控件开关的图片
track:控件开关的轨迹图片
typeface:设置字体类型
switchMinWidth:开关最小宽度
switchPadding:设置开关 与文字的空白距离
switchTextAppearance:设置文本的风格
checked:设置初始选中状态
splitTrack:是否设置一个间隙,让滑块与底部图片分隔(API 21及以上)
showText:设置是否显示开关上的文字(API 21及以上)
SwitchCompat滑动按钮组件
自定义背景
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="true"> <shape android:shape="rectangle"> <corners android:radius="15dp"/> <solid android:color="@color/color_FF5E27"/> </shape> </item> <item android:state_checked="false" > <shape android:shape="rectangle"> <corners android:radius="15dp"/> <solid android:color="@color/gray99"/> </shape> </item> </selector>
设置
app:track="@drawable/selected_switch"
自定义点thumb
<?xml version="1.0" encoding="utf-8"?> <!-- 按钮的选择器,可以设置按钮在不同状态下的时候,按钮不同的颜色 --> <selector xmlns:android="http://schemas.android.com/apk/res/android" > <item android:state_checked="true" android:drawable="@drawable/green_thumb" /> <item android:drawable="@drawable/gray_thumb" /> </selector>
android:thumb="@drawable/dot"
叠堆组件
类似图片叠放在一起的效果
<StackView android:layout_width="100dp" android:layout_height="100dp"></StackView>
单选按钮
<RadioButton android:id="@+id/sick_leave" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="23dp" android:background="@drawable/bg_btn_selector_tow" android:button="@null" android:gravity="center" android:minWidth="80dp" android:minHeight="40dp" android:text="病假" android:textSize="@dimen/font_size_14" android:textColor="@color/fontWhite" />
android:button="@null"这条语句将原来系统的RadioButton图标给隐藏起来。
单选按钮组
只能在多个选择里,选中一个的按钮组件,选择一个后,另外一个选中的会自动取消
<!--单选按钮组--> <RadioGroup android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:checkedButton="@id/a"> <!--android:checkedButton="@id/a" 默认选择值--> <RadioButton android:id="@+id/a" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="A"/> <RadioButton android:id="@+id/b" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="B"/> </RadioGroup>
代码上添加默认选中值
((RadioButton)radioGroup.getChildAt(0)).setChecked(true);
获取选中的值
selectData.getCheckedRadioButtonId();
复选框组件
<CheckBox android:id="@+id/check_agreement" android:text="我已阅读并同意" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true"//默认选中状态
/>
mCheckAgreement = (CheckBox)findViewById(R.id.check_agreement); mCheckAgreement.isChecked();//查询当前选中状态 mCheckAgreement.setChecked(true);//设置默认 mCheckAgreement.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { L.e("点击状态"+isChecked); } });
替换选择图片:
ic_checkbox.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/ic_round_check_orange" android:state_checked="true"></item> <item android:drawable="@drawable/ic_round_check_gray" android:state_checked="false"></item> </selector>
<!--在styles.xml文件里添加 checkbox的图片风格--> <style name="loginCheckbox" parent="@android:style/Widget.CompoundButton.CheckBox"> <item name="android:button">@drawable/ic_checkbox</item> </style>
<CheckBox android:id="@+id/check_agreement" android:text="我已阅读并同意" android:textColor="@color/colorGray3" android:textSize="@dimen/font_size_14" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" style="@style/loginCheckbox"/>
带文字的复选框组件(可能已经废弃了,使用上面的复选框一样可以带文字)
什么?你还在用TextView在加CheckBox实现复选框功能?快使用带文字的复选框试试吧,优点比CheckBox 有更大的点击范围,点击文字也可以支持勾选,用户操作上更舒服。
<CheckedTextView android:layout_width="wrap_content" android:layout_height="?android:attr/listPreferredItemHeightSmall" android:textAppearance="?android:attr/textAppearanceListItemSmall" android:gravity="center_vertical" android:drawableLeft="?android:attr/listChoiceIndicatorMultiple" android:checkMark="?android:attr/listChoiceIndicatorMultiple" android:focusableInTouchMode="true"//在触摸模式下可聚焦,触摸就选中 android:filterTouchesWhenObscured="true"//遮挡时过滤触摸 android:text="@string/order" />
其中:android:drawableLeft控制显示在左边,checkMark控制显示在右边。
?android:attr/listChoiceIndicatorMultiple 表示复选框,?android:attr/listChoiceIndicatorSingle表示单选框
mCheckAgreement.setChecked(true);//设置默认选中 mCheckAgreement.isChecked();//查看选中状态
设置选着框的样式:
selector必须要使用drawable,不能使用color,否者会报xml错误
//incompetence_item_selector xml名称 <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/uncheck" android:state_enabled="true" android:state_focused="true" android:state_pressed="false" /> <item android:drawable="@drawable/check" android:state_enabled="true" android:state_pressed="true" /> <item android:drawable="@drawable/check" android:state_checked="true" android:state_enabled="true" /> <item android:drawable="@drawable/uncheck" /> </selector>
<CheckedTextView android:id="@+id/incompetence_item_ctv" android:layout_width="match_parent" android:layout_height="wrap_content" android:button="@null" android:ellipsize="marquee" android:filterTouchesWhenObscured="true" android:focusableInTouchMode="true" android:gravity="center_vertical" android:padding="@dimen/padding_size_two" android:text="CheckedTextView 注意事项" />
设置背景的selector一定要在代码里面设置,不能再xml中设置:
incompetence_item_ctv.setCheckMarkDrawable(R.drawable.incompetence_item_selector)
双向开关组件ToggleButton
跟你家里的灯的开关按钮一样,它一个按键支持两种状态
<!--双向开关按钮组件--> <ToggleButton android:id="@+id/btn_offAndOn" android:layout_width="match_parent" android:layout_height="wrap_content" android:textOff="关闭功能" android:textOn="启用功能"/>
mBtn = (ToggleButton)findViewById(R.id.btn_offAndOn); mBtn.setOnClickListener(this); @Override public void onClick(View view) { switch (view.getId()){ case R.id.btn_offAndOn: Intent intent = new Intent(MainActivity.this,PhoneServer.class); if (mBtnWiFiAP.isChecked()){ startService(intent); }else { stopService(intent); } break; default: break; }
所属专用适配器
public class GuideAdapter extends PagerAdapter { private List<Integer> mImageIdList = new ArrayList<>(); private View mLastPageView; public GuideAdapter(List<Integer> imageIdList,View lastPageView){ mImageIdList.clear(); this.mImageIdList.addAll(imageIdList); this.mLastPageView = lastPageView; } @Override public int getCount() { if (mLastPageView == null){ return mImageIdList.size(); }else { return mImageIdList.size()+1; } } @Override public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { return view == object; } @NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { L.e("position="+position); L.e("getCount()="+getCount()); if (position == getCount()-1 && mLastPageView != null){ //判断是不是最后一页,如果是就导入一个带有按键的布局 container.addView(mLastPageView); return mLastPageView; }else { //如果不是就使用一个ImageView填充 ImageView imageView = new ImageView(container.getContext()); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setImageResource(mImageIdList.get(position)); container.addView(imageView); return imageView; } } @Override public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { container.removeView((View)object); } }
视图翻页的兄弟ViewFlipper(快速翻页)
这是一个需要创建适配器的View,最常用的场景是在图库里的图片浏览界面,翻页方式为快速拖动
<ViewFlipper android:layout_width="wrap_content" android:layout_height="wrap_content"></ViewFlipper>
自动补全文本框
<MultiAutoCompleteTextView android:layout_width="match_parent" android:layout_height="match_parent" />
输入框自动提示组件
<AutoCompleteTextView android:layout_width="wrap_content" android:layout_height="wrap_content" />
属性 | 对应方法 | 描述 |
---|---|---|
android:completionHint | setCompletionHint(CharSequence) | 设置下拉菜单中的提示标题 |
android:completionHintView | 设置下拉菜单中提示标题的视图 | |
android:completionThreshold | setThreshold(int) | 设置用户至少输入几个字符才会显示提示。默认为 2 个 |
android:dropDownSelector | 设置选中的item背景色 | |
android:dropDownAnchor | setDropDownAnchor(int id) | 它的值是一个View的ID,指定后,AutoCompleteTextView会在这个View下弹出自动提示。 |
android:dropDownWidth | 设置自动提示列表的宽度。 | |
android:dropDownHeight | 设置自动提示列表的高度。 | |
原属性之外的几个常用方法 | ||
android:dropDownHorizontalOffest | 设置下拉菜单与文本框之间的水平偏移,下拉菜单默认与文本框左对齐 | |
adnroid:dropDownVerticalOffest | 设置下拉菜单与文本框之间的垂直偏移,下拉菜单默认紧跟文本框 | |
android:popupBackground | setDropDownBackgroundResource(int) | 设置下拉菜单的背景 |
评分组件(给产品快速评分)
<RatingBar android:layout_width="wrap_content" android:layout_height="wrap_content" />
ProgressBar进度条组件
<!--默认圆环进度条--> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:max="100"/> <!--水平进度条--> <ProgressBar android:layout_width="200dp" android:layout_height="wrap_content" style="?android:attr/progressBarStyleHorizontal" android:max="100"/>
- @android:style/Widget.ProgressBar.Horizontal:水平进度条(可以显示刻度,常用)。
- @android:style/Widget.ProgressBar.Small:小进度条。
- @android:style/Widget.ProgressBar.Large:大进度条。
- @android:style/Widget.ProgressBar.Inverse:不断跳跃、旋转画面的进度条。
- @android:style/Widget.ProgressBar.Large.Inverse:不断跳跃、旋转动画的大进度条。
- @android:style/Widget.ProgressBar.Small.Inverse:不断跳跃、旋转动画的小进度条
- android:max:设置进度的最大值。
- android:progress:设置当前第一进度值。
- android:secondaryProgress:设置当前第二进度值。
- android:visibility:设置是否显示,默认显示。
自定义样式:
1.不确定样式(就是转圈)
android:indeterminateDrawable="" 也可以配置 <animation-list 属性的帧动画
android:indeterminateDrawable="@anim/pull_up_ic"
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@mipmap/ic_rolling" android:fromDegrees="0" android:toDegrees="650" android:pivotX="50%" android:pivotY="50%" android:visible="true" android:duration="3000" android:repeatCount="infinite"> </rotate>
2.进度条样式(可以设置正向和反向进度条)
style="@android:style/Widget.ProgressBar.Horizontal"
android:progressDrawable="@drawable/progress_bar"
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@android:id/background"> <color android:color="@color/colorGray5"/> </item> <item android:id="@android:id/secondaryProgress"> <clip> <shape> <corners android:radius="5dp"/> <gradient android:startColor="@color/colorGray5" android:endColor="@color/colorGray5"/> </shape> </clip> </item> <item android:id="@android:id/progress"> <clip android:clipOrientation="horizontal" android:gravity="right"> <shape> <corners android:radius="5dp"/> <gradient android:startColor="@color/colorDarkGreen" android:endColor="@color/colorDarkGreen"/> </shape> </clip> </item> </layer-list>
此样式为反向进度条,改变绘制方向的属性为android:gravity="right"
两个方向圆角
效果图
xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<color android:color="@android:color/transparent"/>
</item>
<item android:id="@android:id/secondaryProgress">
<color android:color="@android:color/transparent"/>
</item>
<item android:id="@android:id/progress">
<scale android:scaleWidth="100%"
android:drawable="@drawable/main_progress_bar_ct"/>
</item>
</layer-list>
main_progress_bar_ct.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/main_color_BF6700" />
<corners android:radius="10dp" />
</shape>
数字选择器组件(自定义选择器)
<NumberPicker android:layout_width="match_parent" android:layout_height="match_parent"></NumberPicker>
日历组件
<CalendarView android:layout_width="match_parent" android:layout_height="match_parent"></CalendarView>
计时器组件
<Chronometer android:id="@+id/cRecordPopTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginBottom="@dimen/d24" android:fontFamily="sans-serif-light" android:textColor="@color/fontHint" android:textSize="@dimen/s13" tools:targetApi="jelly_bean" />
Chronometer mChronometer; mChronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() { @Override public void onChronometerTick(Chronometer cArg) { long time =System.currentTimeMillis() - cArg.getBase(); Date d = new Date(time); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss", Locale.US); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); timeView.setText(sdf.format(d)); } }); timeView.setBase(System.currentTimeMillis()); timeView.start();
时间显示组件
<TextClock android:id="@+id/time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:format24Hour="yyyy年MM月dd日 HH时mm分ss秒" android:format12Hour="yyyy年MM月dd日 hh时mm分ss秒" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent"/>
android:format24Hour="HH:mm" HH为24小时格式
android:format12Hour="hh:mm" hh为12小时格式
如果你希望强制显示24小时格式可以将 format12Hour 里的时间设置HH,同理强制12小时可以相反设置
android:format12Hour="aa" 显示AM/PM 上午下午
建议12小时和24小时格式都需要写上,否则会出现机器设置为12小时制,你设置为24小时制,导致年月日无法显示的问题。
<TextClock android:id="@+id/tc_eeee" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/white" android:format12Hour="EEEE" android:format24Hour="EEEE" android:textSize="16sp" />
EEEE是星期
setFormatHour(tc_hhmm,"hh:mm");//当前时钟 setFormatHour(tc_yyyymmdd,"yyyy年M月dd日");//年月日 setFormatHour(tc_eeee,"EEEE");//星期
时间选择器组件
<TimePicker android:id="@+id/tiem_picker" android:layout_width="wrap_content" android:layout_height="wrap_content" android:timePickerMode="spinner" android:layout_gravity="center" android:numbersTextColor="@color/theme_color" android:scaleY="1.5" android:scaleX="1.5"/>
//时间值传入,并且设置修改时间选择器的时间显示 public void timeDataInit(){ Intent intent = getIntent(); mHour = intent.getIntExtra(KEY_HOUR,-1); mMinute = intent.getIntExtra(KEY_MINUTE,-1); if(mHour != -1 && mMinute != -1){ mTiemPicker.setCurrentHour(mHour); mTiemPicker.setCurrentMinute(mMinute); }else { Log.e("SelectionTiem","传入的时间值为空"); } } @Override public void initData() { //将时间选择器里的值传出 mTiemPicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() { @Override public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { mHour = hourOfDay; mMinute = minute; } }); }
时间选择器对话框组件
new TimePickerDialog(this,new TimePickerDialog.OnTimeSetListener() { @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { houre = hourOfDay; WuraoActivity.this.minute = minute; if (WuraoActivity.this.minute < 10){ endTimeTv.setText(houre+":"+"0"+WuraoActivity.this.minute); }else { endTimeTv.setText(houre+":"+WuraoActivity.this.minute); } } }, 0, 0, true).show();
日期选择器组件
<DatePicker android:layout_width="wrap_content" android:layout_height="wrap_content"></DatePicker>
日期选择器对话框组件
例子一:
/** * 日期选择 * @param activity * @param themeResId * @param tv * @param calendar */ public static void showDatePickerDialog(Activity activity, int themeResId, final TextView tv, Calendar calendar) { new DatePickerDialog(activity , themeResId,new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { // 此处得到选择的时间,可以进行你想要的操作 tv.setText("您选择了:" + year + "年" + (monthOfYear+1)+ "月" + dayOfMonth + "日"); } } // 设置初始日期 , calendar.get(Calendar.YEAR) ,calendar.get(Calendar.MONTH) ,calendar.get(Calendar.DAY_OF_MONTH)).show(); }
例子二:
DatePickerDialog datePickerDialog = new DatePickerDialog(TStudentAttendanceActivity.this,new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { } },2019,1,1); datePickerDialog.updateDate(2019,1,1); datePickerDialog.show();
设置时间选择范围:
DatePicker datePicker = mDatePickerDialog.getDatePicker(); datePicker.setMaxDate(System.currentTimeMillis()-1000);//注意时间不能等于当前时间,否则会报错 datePicker.setMinDate(1);
年月选择对话框(隐藏日期选择,修改分割线颜色)
public void showDatePickerDialog() { if (mDatePickerDialog == null) { mDatePickerDialog = new DatePickerDialog(TStudentAttendanceStatisticsActivity.this,DatePickerDialog.THEME_HOLO_LIGHT, new DatePickerDialog.OnDateSetListener() {//重点!DatePickerDialog.THEME_HOLO_LIGHT 这里是选择日期对话框风格 @Override public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR,year); calendar.set(Calendar.MONTH,month); calendar.set(Calendar.DAY_OF_MONTH,dayOfMonth); mCurrentTime = calendar.getTimeInMillis(); } }, 2019,1,1); } mDatePickerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { } }); DatePicker datePicker = mDatePickerDialog.getDatePicker(); datePicker.setMaxDate(System.currentTimeMillis()-10);//设置最大选择日期 ((ViewGroup) ((ViewGroup) datePicker.getChildAt(0)).getChildAt(0)).getChildAt(2).setVisibility(View.GONE);//隐藏日期 setDatePickerDividerColor(datePicker);//修改分割线颜色 mDatePickerDialog.updateDate(TimeUtil.getYear(mCurrentTime),TimeUtil.getMonth(mCurrentTime),TimeUtil.getDayOfMonth(mCurrentTime)); mDatePickerDialog.show(); } /** * 设置时间选择器的分割线颜色 * @param datePicker */ private void setDatePickerDividerColor(DatePicker datePicker) { // Divider changing: // 获取 mSpinners LinearLayout llFirst = (LinearLayout) datePicker.getChildAt(0); // 获取 NumberPicker LinearLayout mSpinners = (LinearLayout) llFirst.getChildAt(0); for (int i = 0; i < mSpinners.getChildCount(); i++) { NumberPicker picker = (NumberPicker) mSpinners.getChildAt(i); Field[] pickerFields = NumberPicker.class.getDeclaredFields(); for (Field pf : pickerFields) { if (pf.getName().equals("mSelectionDivider")) { pf.setAccessible(true); try { pf.set(picker, new ColorDrawable(Color.parseColor("#fea239")));//设置分割线颜色 } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (Resources.NotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } break; } } } }
效果图:
视频播放组件
<VideoView android:layout_width="wrap_content" android:layout_height="wrap_content" />
视频动画组件
在Android中,ViewAnimator
是FrameLayout
的一个子类,用来做Views之间的切换。它是一个变换控件的
元素,帮助我们在Views之间(如TextView
, ImageView
或者其他layout)添加变换。它有助于在屏幕view添加动画。ViewAnimator
可以在两个及以上Views上平滑的切换,通过合适动画,提供从一个View到另外一个View变换的方式。
<ViewAnimator android:layout_width="wrap_content" android:layout_height="wrap_content"></ViewAnimator>
视图存根组件
要显示某些控件了,在加载,节省内存~ 跟android:visibility="gone"属性说拜拜
<ViewStub android:layout_width="wrap_content" android:layout_height="wrap_content" />
曲面视图 SurfaceView,SurfaceTexture,TextureView,
首先SurfaceView, SurfaceTexture,TextureView都是为了实现单独刷新帧数的View(与UI线程的帧数无关).
- SurfaceView API 1.0 加入
- GLSurfaceView API 1.5加入
- SurfaceTexture API 11加入
- TextureView Android4.0(API level 14)加入
SurfaceView
从Android 1.0(API level 1)时就有 。它继承自类View,因此它本质上是一个View。但与普通View不同的是,它有自己的Surface。我们知道,一般的Activity包含的多个View会组成View hierachy的树形结构,只有最顶层的DecorView,也就是根结点视图,才是对WMS可见的。这个DecorView在WMS中有一个对应的WindowState。而SurfaceView就是在Window上挖一个洞,它就是显示在这个洞里,其他的View是显示在Window上,所以View可以显示在 SurfaceView之上,你也可以添加一些层在SurfaceView之上。(例如在上面设置一些按钮控件)我们知道View的更新只能在UI线程中,所以使用自定义View没办法这么做,但是SurfaceView就可以了。它一个很好用的地方就是允许其他线程(不是UI线程)绘制图形(使用Canvas),根据它这个特性,你就可以控制它的帧数,你如果让这个线程1秒执行50次绘制,那么最后显示的就是50帧。(一般使用thread.sleep(20);代表一秒刷新50次)SurfaceView能够自己控制执行帧数的对象,这样可以弥补View的不足,因为有时候View的帧数太低了,这会导致画面效果不顺畅,影响体验效果。
SurfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面。那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中 thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。
所以基于以上,根据游戏特点,一般分成两类
1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。
本质区别:
View:必须在UI的主线程中更新画面,用于被动更新画面。
surfaceView:UI线程和子线程中都可以。在一个新启动的线程中重新绘制画面,主动更新画面。
<SurfaceView android:layout_width="wrap_content" android:layout_height="wrap_content" />
SurfaceHolder surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } });
SurfaceTexture
TextureView
<TextureView android:layout_width="wrap_content" android:layout_height="wrap_content" />
使用TextureView需要开启硬件加速功能.开启硬件加速方法如下:
在AndroidManifest.xml 清单文件里,你需要实现相机功能的activity添加 android:hardwareAccelerated="true"
SurfaceTextureListener接口
mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { //可用 //此处一般加载内容,比如相机预览图像 } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { //尺寸变化 } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { //销毁 return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { //更新 } });
QuickContactBadge
关联联系人组件
badge = (QuickContactBadge) findViewById(R.id.badge); // 指定联系人的电话号码 // 先搜索该号码,如果没有则提醒是否添加到联系人 // 第二个参数为延迟匹配,若为true,则直到被点击时才会查找该地址 badge.assignContactFromPhone("15958455037", false);
end
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/9708585.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具