一、进度条类组件
1、进度条(ProgressBar)
- 就两种进度条:水平进度条和环形的进度条
- 安卓内置多种的进度条风格(style)可以选择
- 最重要的属性就是:max(最大进度) 和 progress(当前进度)
水平进度条的动态实现
- 布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".MainActivity"
android:background="#49CED3">
<ProgressBar
android:id="@+id/pro1"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_margin="20dp"
android:max="100" />
</RelativeLayout>
- java 文件
public class MainActivity extends AppCompatActivity {
private ProgressBar progressBar;
private int progress;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = (ProgressBar) findViewById(R.id.pro1);
//handler用于线程之间的通讯
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x111) {
progressBar.setProgress(progress);
} else {
Toast.makeText(MainActivity.this, "耗时操作已经完成!", Toast.LENGTH_LONG).show();
progressBar.setVisibility(View.GONE);
}
}
};
//开启新的线程来更新进度条的状态
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
progress = doWork();
Message msg = new Message();
if (progress < 100) {
msg.what = 0x111;
handler.sendMessage(msg);
} else {
msg.what = 0x000;
handler.sendMessage(msg);
break;
}
}
}
//此方法用于产生一个随机的进度值
private int doWork() {
progress += Math.random() * 10;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return progress;
}
}).start();
}
}
2、拖动条(SeekBar)
- 就是进度条的一个子类,可以通过拖动改变一些属性
- 基本的属性和进度条是一样的,max设置最大,progress 设置当前的一个值
- setOnSeekBarChangeListener 设置拖动变化的监听器
- 练习示例:美图秀秀改变图片的透明度
3、星级评分条(RatingBar)
- 就是淘宝评分的那个条条,和进度条是类似的
- 最重要的几个属性:numStar、stepSize(默认可以有半颗星)、rating、isIndicator(是否只能看)
二、图像类组件
1、ImageView(图像视图)
src & background
- background通常指的都是背景,而src指的是内容
- 当使用src填入图片时,是按照图片大小直接填充,并不会进行拉伸
- 而使用background填入图片,则是会根据ImageView给定的宽度来进行拉伸
- 可以通过
android:alpha="0.5"
来设置图片的透明度,实测无论是src还是bg 都是有效果的
解决blackground拉伸导致图片变形的方法
- 对于通过java动态加载ImageView的,只要在添加View的时候,把大小写写死就可以了
LinearLayout.LayoutParams layoutParam = new LinearLayout.LayoutParams(48, 48);
layout.addView(ibtnPen, layoutParam);
- 通过xml布局的方式引入ImageView的,drawable 文件夹下,编写 bitmap 资源,然后通过background属性引入就可以了,下面的就是bitmap资源 fg_bg.xml 的代码
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fg_bg"
android:gravity="top"
android:src="@drawable/fg"
android:tileMode="repeat" >
</bitmap>
adjustViewBounds设置视图边界
- 通过下面的设置可以实现长宽的等比缩放
android:layout_width="wrap_content"
android:layout_width="wrap_content"
android:adjustViewBounds="true"
android:maxHeight="400px"
android:maxWidth="400px"
scaleType设置缩放类型
- 可选的属性值的如下
fitXY:对图像的横向与纵向进行独立缩放,使得该图片完全适应ImageView,但是图片的横纵比可能会发生改变
fitStart:保持纵横比缩放图片,知道较长的边与Image的编程相等,缩放完成后将图片放在ImageView的左上角
fitCenter:同上,缩放后放于中间;
fitEnd:同上,缩放后放于右下角;
center:保持原图的大小,显示在ImageView的中心。当原图的size大于ImageView的size,超过部分裁剪处理。
centerCrop:保持横纵比缩放图片,知道完全覆盖ImageView,可能会出现图片的显示不完全
centerInside:保持横纵比缩放图片,直到ImageView能够完全地显示图片
matrix:默认值,不改变原图的大小,从ImageView的左上角开始绘制原图, 原图超过ImageView的部分作裁剪处理
tint
属性可以设置着色,就是在原图的上面加一层颜色,一定要有透明度哟,不然原图就被完全覆盖了
2、图像切换器(ImageSwitcher)
- 这个就是类似安卓系统中相册一样的功能通过点击或者滑动进行图片的切换
我的相册的实现
- 布局文件
<RelativeLayout 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"
tools:context=".MainActivity">
<ImageSwitcher
android:id="@+id/is1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
- java文件:ImageSwitcher通过内置的视图工厂(ViewFactory)进行图像视图的创建
public class MainActivity extends AppCompatActivity {
private int[] imagePath = new int[]{
R.drawable.img01, R.drawable.img02, R.drawable.img03,
R.drawable.img04, R.drawable.img05, R.drawable.img06
};
private int index;
private ImageSwitcher is;
private float touchDownX;
private float touchUpX;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
is = (ImageSwitcher) findViewById(R.id.is1);
is.setFactory(new ImageSwitcher.ViewFactory() {
@Override
public View makeView() {
ImageView iv = new ImageView(MainActivity.this);
iv.setImageResource(imagePath[index]);
return iv;
}
});
is.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
touchDownX = event.getX();
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
touchUpX = event.getX();
//手指离开的时候进行具体的处理
if (touchUpX - touchDownX > 100) {
//这里的情况是手指是从左往右滑动,就是上一个图像的操作
index = index == 0 ? imagePath.length - 1 : index - 1;
is.setInAnimation(AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_in_left));
is.setOutAnimation(AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_out_right));
is.setImageResource(imagePath[index]);
} else if (touchDownX - touchUpX > 100) {
index = index == imagePath.length - 1 ? 0 : index + 1;
is.setInAnimation(AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_in_right));
is.setOutAnimation(AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_out_left));
is.setImageResource(imagePath[index]);
}
return true;
}
return false;
}
});
}
}
3、网格视图(GridView)
预备知识:适配器(Adapter)
- dapter的作用是将各种数据以合适的形式填充到View中给用户看
- Adapter比较常用的几个是:BaseAdapter,ArrayAdapter,SimpleAdapter
- 三个常用的适配器中BaseAdapter是抽象类需要自己实现,其他两个都是可以直接使用的
- ArrayAdapter(数组适配器)使用有一定的局限性,只能显示一行文本数据,数据源可以是数组或者集合
- SimpleAdapter(简单适配器)可以实现多行文本和图文混排,需要注意5个参数代表的含义
- BaseAdapter需要继承使用,最重要的是要重写 getView 方法,优化的写法如下
- 具体Adapter使用细节参考博客:https://www.cnblogs.com/huolan/p/5126794.html
用网格视图实现类似QQ相册的界面
- 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:orientation="vertical"
tools:context=".MainActivity">
......
<GridView
android:id="@+id/gv1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:horizontalSpacing="10dp"
android:verticalSpacing="10dp"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"/>
</LinearLayout>
- java文件(用 BaseAdapter注入数据)
public class MainActivity extends AppCompatActivity {
private int[] picture = new int[]{
R.drawable.img01, R.drawable.img02, R.drawable.img03,
R.drawable.img04, R.drawable.img05, R.drawable.img06
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gv = (GridView) findViewById(R.id.gv1);
gv.setAdapter(new ImageAdapter(this));
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
public ImageAdapter(Context context) {
mContext = context;
}
@Override
public int getCount() {
return picture.length;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = null;
if (convertView == null) {
imageView = new ImageView(MainActivity.this);
imageView.setLayoutParams(new GridView.LayoutParams(250, 225));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(picture[position]);
return imageView;
}
}
}
其中 getCount 方法需要重写,不然最后无法正确显示
三、列表类组件
1、下拉列表(Spinner)
- 就是和 html 中的 select 元素一样的东西,数据源的部分可以通过xml资源文件来实现,也可以使用 Adapter
XML文件注入数据
- 布局文件
<Spinner
android:id="@+id/sp1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="@array/datas">
</Spinner>
- xml数据源(values文件夹下面的arrays xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="datas">
<item>全部</item>
<item>语文</item>
<item>数学</item>
<item>外语</item>
<item>生物</item>
<item>化学</item>
<item>物理</item>
</string-array>
</resources>
ArrayAdapter注入数据
public class MainActivity extends AppCompatActivity {
private String[] datas = new String[]{
"全部","语文-1","英语-2","数学-3"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Spinner spinner = (Spinner)findViewById(R.id.sp1);
ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_spinner_dropdown_item,datas);
spinner.setAdapter(adapter);
}
}
2、列表视图(ListView)
微信联系人列表实现
- 主布局文件
<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:orientation="vertical"
tools:context=".MainActivity">
<ImageView
android:layout_width="412dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@mipmap/wei_top" />
<ListView
android:id="@+id/lv1"
android:layout_width="match_parent"
android:layout_height="500dp"></ListView>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@mipmap/wei_down" />
</LinearLayout>
- 列表项布局文件:就是前面一个头像,后面联系人名称
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingBottom="10dp" />
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="50dp"
android:paddingTop="20dp"
android:textSize="36sp" />
</LinearLayout>
- java代码:通过 adapter 注入数据
public class MainActivity extends AppCompatActivity {
private int[] pics = new int[]{
R.mipmap.img01, R.mipmap.img02, R.mipmap.img03, R.mipmap.img04,
R.mipmap.img05, R.mipmap.img06, R.mipmap.img07, R.mipmap.img08, R.mipmap.img09
};
private String[] names = new String[]{
"张三", "李四", "王麻子", "李老栓", "潘驼背", "樊傻儿", "毛子", "霍得转", "叮叮猫"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(R.id.lv1);
List<Map<String, Object>> listItem = new ArrayList<>();
for (int i = 0; i < pics.length; i++) {
Map<String, Object> item = new HashMap<>();
item.put("image", pics[i]);
item.put("name", names[i]);
listItem.add(item);
}
SimpleAdapter adapter = new SimpleAdapter(this, listItem, R.layout.main,
new String[]{"image", "name"},
new int[]{R.id.iv1, R.id.tv1});
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Map<String, Object> map = (Map<String, Object>) parent.getItemAtPosition(position);
Toast.makeText(MainActivity.this, map.get("name").toString(), Toast.LENGTH_SHORT).show();
}
});
}
}
3、通用适配器(Adapter)的打造
四、通用组件
1、滚动视图(ScrollView)
- 这里的ScrollView默认的是垂直滚动的视图,HorizontalScrollView才是水平的滚动视图
书籍目录滚动视图实现
- 这个例子最主要的组件就是两个线性管理器和一个ScrollView
- ll1是根布局管理器,他里面直接的子组件是ScrollView
- ll2是ScrollView里面包含的布局管理器,ll2里面还有自己的子组件
LinearLayout ll =(LinearLayout)findViewById(R.id.ll);
LinearLayout ll2 = new LinearLayout(this);
ll2.setOrientation(LinearLayout.VERTICAL);
ScrollView sv = new ScrollView(this);
ImageView iv = new ImageView(this);
iv.setImageResource(R.mipmap.cidian);
iv.setAdjustViewBounds(true);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(1080,1080);
iv.setLayoutParams(params);
TextView tv = new TextView(this);
tv.setText(R.string.cidian);
tv.setTextSize(24);
ll2.addView(iv);
ll2.addView(tv);
sv.addView(ll2);
ll.addView(sv);
2、选项卡
微信表情商店实现
-
基本步骤
- 在布局文件中添加 TabHost、TabWidget 和 TabContent 的组件
- 这里 tabHost 本质就是一个布局管理器,是FrameLayout的子类
- 三个组件的id(tabhost、tabs、tabcontent)是安卓内置的,不能自定义
- 编写个标签页的 XML 布局文件
- 在 java 中获取并初始化 TabHost
- 为 TabHost 添加标签页
-
XML布局文件
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"></TabWidget>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</LinearLayout>
</TabHost>
- java 文件:其中的 tab1 和 tab2 就是两个相应的标签页的布局文件
TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
tabHost.setup();
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.tab1,tabHost.getTabContentView());
inflater.inflate(R.layout.tab2,tabHost.getTabContentView());
tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("精选").setContent(R.id.left));
tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("自定义").setContent(R.id.right));
tabHost.setCurrentTab(0);
3、ViewFlipper(翻转视图)
- ViewFlipper是Android自带的一个多页面管理控件,且可以自动播放
- 和ViewPager不同,ViewPager是一页页的,而ViewFlipper则是一层层的
- 用来实现进入应用后的引导页,或者用于图片轮播
图片自动播放
- 常用方法
- setInAnimation:设置View进入屏幕时使用的动画
- setOutAnimation:设置View退出屏幕时使用的动画
- showNext:调用该方法来显示ViewFlipper里的下一个View
- showPrevious:调用该方法来显示ViewFlipper的上一个View
- setFilpInterval:设置View之间切换的时间间隔
- setFlipping:使用上面设置的时间间隔来开始切换所有的View,切换会循环进行
- stopFlipping:停止View切换
- xml布局
<RelativeLayout 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"
tools:context=".MainActivity">
<ViewFlipper
android:id="@+id/vf"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:flipInterval="2000"
android:inAnimation="@anim/right_in"
android:outAnimation="@anim/right_out">
<ImageView
android:id="@+id/iv1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/ic_help_view_1" />
<ImageView
android:id="@+id/iv2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/ic_help_view_2" />
<ImageView
android:id="@+id/iv3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/ic_help_view_3" />
<ImageView
android:id="@+id/iv4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/ic_help_view_4" />
</ViewFlipper>
</RelativeLayout>
- 动画文件
<?-right_in xml 文件--?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="2000"
android:fromXDelta="100%p"
android:toXDelta="0"></translate>
</set>
<?-right_out xml 文件--?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="2000"
android:fromXDelta="0"
android:toXDelta="-100%p"></translate>
</set>
- java文件
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewFlipper vf = (ViewFlipper) findViewById(R.id.vf);
vf.startFlipping();
}
}
手势滑动切换
- 这一部分代码参考后面的手势部分
4、ViewPager(翻转视图)
ViewPager简介
- ViewPager就是一个简单的页面切换组件,我们可以往里面填充多个View,然后我们可以左 右滑动,从而切换不同的View
- 需要一个Adapter (适配器)将我们的View和ViewPager进行绑定,而ViewPager则有一个特定的Adapter(PagerAdapter)
- Google官方建议我们使用Fragment来填充ViewPager,这样 可以更加方便的生成每个Page,以及管理每个Page的生命周期
- 提供了两个Fragment 专用的Adapter:FragmentPageAdapter和FragmentStatePagerAdapter
- FragmentPageAdapter和FragmentStatePagerAdapter 比较
- 前者会缓存当前和前后的两个Fragment,后者只要Fragment对用户不可见就会销毁,只保留Fragment的状态
- FragmentPageAdapter适合固定的页面较少的场合,而FragmentStatePagerAdapter则适合于页面较多或者页面内容非常复杂(需占用大量内存)的情况!
ViewPager使用(PageAdapter使用)
-
pageAdapter方法
- getCount():获得viewpager中有多少个view
- destroyItem():移除一个给定位置的页面
- instantiateItem(): 将给定位置的view添加到ViewGroup(容器)中,创建并显示出来 ;返回一个代表新增页面的Object(key),通常都是直接返回view本身就可以了
- isViewFromObject():判断instantiateItem(ViewGroup, int)函数所返回来的object与一个页面视图是否是代表的同一个视图(即它俩是否是对应的,对应的表示同一个View),通常我们直接写 return view == object!
-
基础使用
-
实现类似tabhost的效果