ListView
一、什么是ListView,為什么要使用ListView?
ListView
可以一列一列的顯示圖標(biāo)和文本。(類(lèi)似QQ聊天和翻閱微博消息)
ListView
允許用戶通過(guò)手指上下滑動(dòng)的方式將屏幕外的數(shù)據(jù)滾動(dòng)到屏幕內(nèi),同時(shí)屏幕上原有的數(shù)據(jù)則會(huì)滾動(dòng)出屏幕。
二、ListView的使用
1、創(chuàng)建實(shí)體類(lèi)(model、entity、bean)
public class Fruit {
private String name;
private int imageId;
public Fruit(String name, int imageId) {
this.name = name;
this.imageId = imageId;
}
public String getName() {
return name;
}
public int getImageId() {
return imageId;
}
2、xml布局
-
Item
布局(根據(jù)實(shí)體類(lèi)的部分或全部需要顯示的屬性布局)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="測(cè)試" />
</LinearLayout>
-
Activity
布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ListViewActivity">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
3、Adapter
public class FruitAdapter extends BaseAdapter {
private List<Fruit> mFruits;//列表數(shù)據(jù)源
private Context mContext;//需要傳入的Context
FruitAdapter(Context context) {
mContext = context;
}
//新增數(shù)據(jù)
public void initData(List<Fruit> fruits) {
if (mFruits == null){
mFruits = new ArrayList<>();
}
if (fruits == null) {
return;
}
mFruits.addAll(fruits);
notifyDataSetChanged();//記得刷新控件
}
@Override
public int getCount() {
return mFruits == null ? 0 : mFruits.size();
}
@Override
public Fruit getItem(int i) {
return mFruits.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
/**
* @param position 選擇的第幾個(gè)Item的位置
* @param convertView 展示在界面上的一個(gè)item
* @param parent 裝載convertView的父視圖
* @return 當(dāng)前的Item
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Fruit fruit = getItem(position);
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.item, null);//固定寫(xiě)法
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.fruitName.setText(fruit.getName());
viewHolder.fruitImage.setImageResource(fruit.getImageId());
return convertView;
}
class ViewHolder {
ImageView fruitImage;
TextView fruitName;
private ViewHolder(View view) {
fruitImage = view.findViewById(R.id.iv);
fruitName = view.findViewById(R.id.tv);
}
}
}
添加數(shù)據(jù)之后記得刷新adapter
4、Activity
public class ListViewActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();//初始化數(shù)據(jù)源
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_view);
ListView listView = findViewById(R.id.list_view);
//添加數(shù)據(jù)
init();
//生成適配器(Item已經(jīng)在Adapter中綁定好了,只需入當(dāng)前Context)并傳入數(shù)據(jù)
FruitAdapter adapter = new FruitAdapter(this);
adapter.initData(fruitList);
//ListView綁定適配器
listView.setAdapter(adapter);
}
/**
* 初始化,添加數(shù)據(jù)
*/
private void init() {
for (int i = 0; i < 2; i++) {
Fruit apple = new Fruit("Apple", R.drawable.ic_launcher_background);
fruitList.add(apple);
Fruit banana = new Fruit("Banana", R.drawable.ic_launcher_background);
fruitList.add(banana);
Fruit orange = new Fruit("Orange", R.drawable.ic_launcher_background);
fruitList.add(orange);
Fruit watermelon = new Fruit("Watermelon", R.drawable.ic_launcher_background);
fruitList.add(watermelon);
Fruit pear = new Fruit("Pear", R.drawable.ic_launcher_background);
fruitList.add(pear);
Fruit grape = new Fruit("Grape", R.drawable.ic_launcher_background);
fruitList.add(grape);
Fruit pineapple = new Fruit("Pineapple", R.drawable.ic_launcher_background);
fruitList.add(pineapple);
Fruit strawberry = new Fruit("Strawberry", R.drawable.ic_launcher_background);
fruitList.add(strawberry);
Fruit cherry = new Fruit("Cherry", R.drawable.ic_launcher_background);
fruitList.add(cherry);
Fruit mango = new Fruit("Mango", R.drawable.ic_launcher_background);
fruitList.add(mango);
}
}
}
總結(jié):①. 先根據(jù)數(shù)據(jù)類(lèi)Entity
型確定Item,然后對(duì)Item和Activity進(jìn)行Xml布局。
②. Adapter繼承于BaseAdapter(Adapter中要傳入Context
,Entity
數(shù)據(jù)源,Item布局
的Id),先初始化Context
和Entity
數(shù)據(jù)源。在構(gòu)造器中傳入Context
;寫(xiě)一個(gè)initData()
的方法,將數(shù)據(jù)傳入Adapter;在重寫(xiě)B(tài)aseAdapter的四個(gè)方法的getView()
方法中綁定Item的各個(gè)視圖,對(duì)視圖進(jìn)行相關(guān)操作。ViewHolder
當(dāng)然也是不可少的
③. 在Activity中先new Adapter(this)傳入當(dāng)前的context
,Entity
數(shù)據(jù)通過(guò)adapter.initData()將數(shù)據(jù)傳入Adapter中,Adapter通過(guò)ListView.setAdapter(adapter)將適配器和ListView
綁定起來(lái)。
處理好的數(shù)據(jù)要傳入Adapter,通過(guò)adapter的getView()才能顯示出來(lái)
三、ListView的常用屬性
android:divider="@null":除掉分隔線。也可以用該屬性為分隔線添加不同顏色,圖片。
android:dividerHeight:設(shè)置分割線的高度
android:footerDividersEnabled="false",headerDividersEnabled="false":除掉頂部、底部分隔線。
android:scrollbars="none":除掉滾動(dòng)條
android: fadingEdge="none":除掉上下邊的陰影
android: cacheColorHint:拖動(dòng)時(shí)的背景顏色
android: listSelector:Item點(diǎn)擊時(shí)的背景。
android: transcriptMode="alwaysScroll":出現(xiàn)新條目時(shí),自動(dòng)滾動(dòng)到可見(jiàn)的新條目處。
android: choiceMode:子item的選擇模式。
~這樣看似復(fù)雜,其實(shí)和實(shí)際工作比起來(lái)復(fù)雜程度還是差了一點(diǎn)。但是工作的基本思路也是這樣的,可以按照這樣的思維寫(xiě)下去
~對(duì)了,ListView
可以對(duì)整個(gè)Item
設(shè)置點(diǎn)擊事件,和Button的點(diǎn)擊操作類(lèi)似,有興趣可以自己試一試
~Item
布局和Adapter
可以用Android Studio自帶的simple_list_item_1和ArrayAdapter<>,使用起來(lái)更加簡(jiǎn)單
GridView
一、什么是GridView,它和ListView的區(qū)別?
GridView
(網(wǎng)格視圖)是按照行列的方式來(lái)顯示內(nèi)容的,一般用于顯示圖片,圖片文字等內(nèi)容,比如實(shí)現(xiàn)十六宮格,九宮格,四宮格等,用GridView是首選,也是最簡(jiǎn)單的。
GridView
和ListView
的主要區(qū)別在于ListView
不能直接進(jìn)行網(wǎng)格布局,而GridView
可以
二、GridView的使用
1、創(chuàng)建實(shí)體類(lèi)(model、entity、bean) 同上
2、xml布局
-
Item
布局 同上 -
Activity
布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<GridView
android:id="@+id/grid_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnWidth="90dp"
android:numColumns="3"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp" />
</LinearLayout>
3、Adapter(同上)
4、Activity(同上,只需要將ListView替換為GridView就可以了)
總結(jié):與ListView的使用方法幾乎一毛一樣,網(wǎng)格布局的時(shí)候就用GridView
三、GridView的屬性
- android:columnWidth:設(shè)置列的寬度
- android:gravity:組件對(duì)其方式
- android:horizontalSpacing:水平方向每個(gè)單元格的間距
- android:verticalSpacing:垂直方向每個(gè)單元格的間距
- android:numColumns:設(shè)置列數(shù)
- android:stretchMode:設(shè)置拉伸模式,可選值如下: none:不拉伸;spacingWidth:拉伸元素間的間隔空隙 columnWidth:僅僅拉伸表格元素自身 spacingWidthUniform:既拉元素間距又拉伸他們之間的間隔空襲
RecyclerView
一、什么是RecyclerView,它和ListView的區(qū)別?
RecyclerView可以說(shuō)是一個(gè)增強(qiáng)版的ListView,不僅可以輕松實(shí)現(xiàn)和ListView同樣的效果,還優(yōu)化了ListView中存在的各種不足之處。
二、RecyclerView的使用
1、添加依賴
implementation 'com.android.support:recyclerview-v7:27.1.1' //RecyclerView
2、創(chuàng)建實(shí)體類(lèi)(model、entity、bean)
package com.example.administrator.recyclerview;
public class Fruit {
private String name;
private int imageId;
public Fruit(String name, int imageId) {
this.name = name;
this.imageId = imageId;
}
public String getName() {
return name;
}
public int getImageId() {
return imageId;
}
}
3、xml布局
- Item布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_fruit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher_background" />
<TextView
android:id="@+id/tv_fruit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="水果" />
</LinearLayout>
- Activity布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
4、Adapter(重點(diǎn))
package com.example.administrator.recyclerview;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List<Fruit> mFruitList;
public FruitAdapter (){
}
//添加數(shù)據(jù),必要時(shí)候刷新
public void addData(List<Fruit> data){
if (mFruitList == null){
mFruitList = new ArrayList<>();
}
if (data != null){
int startSize = mFruitList.size();
mFruitList.addAll(data);
int endSize = mFruitList.size();
notifyItemRangeChanged(startSize, endSize - startSize);//范圍刷新新添加的數(shù)據(jù)
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//綁定Item
View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler, parent, false);
ViewHolder viewHolder = new ViewHolder(inflate);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
//給Item的布局控件賦值
holder.textView.setText(mFruitList.get(position).getName());
holder.imageView.setImageResource(mFruitList.get(position).getImageId());
}
@Override
public int getItemCount() {
return mFruitList == null ? 0 : mFruitList.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
TextView textView;
ImageView imageView;
ViewHolder(View view) {
super(view);
textView = view.findViewById(R.id.tv_fruit);
imageView = view.findViewById(R.id.iv_fruit);
}
}
}
RecyclerView擁有多種Item的刷新方式:
- notifyDataSetChanged();//數(shù)據(jù)源改變后刷新整個(gè)列表
- notifyDataSetChanged();//刷新整個(gè)列表
- notifyItemRangeChanged(startSize, endSize - startSize);//范圍刷新新添加的數(shù)據(jù)
- notifyItemChanged();//指定刷新某個(gè)位置的Item
- notifyItemMoved();//移動(dòng)Item
等等等等
5、Activity
package com.example.administrator.recyclerview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private FruitAdapter adapter;
private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recycler_view);
//準(zhǔn)備數(shù)據(jù)
adapter = new FruitAdapter();
initData();
adapter.addData(fruitList);
//RecyclerView布局
LinearLayoutManager manager = new LinearLayoutManager(this);
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
// GridLayoutManager manager = new GridLayoutManager(this,3); 網(wǎng)格布局
// StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL); 瀑布布局
recyclerView.setLayoutManager(manager);
recyclerView.setAdapter(adapter);
}
private void initData() {
Fruit apple = new Fruit("Apple", R.drawable.ic_launcher_background);
fruitList.add(apple);
Fruit banana = new Fruit("Banana", R.drawable.ic_launcher_background);
fruitList.add(banana);
Fruit orange = new Fruit("Orange", R.drawable.ic_launcher_background);
fruitList.add(orange);
Fruit watermelon = new Fruit("Watermelon", R.drawable.ic_launcher_background);
fruitList.add(watermelon);
Fruit pear = new Fruit("Pear", R.drawable.ic_launcher_background);
fruitList.add(pear);
Fruit grape = new Fruit("Grape", R.drawable.ic_launcher_background);
fruitList.add(grape);
Fruit pineapple = new Fruit("Pineapple", R.drawable.ic_launcher_background);
fruitList.add(pineapple);
Fruit strawberry = new Fruit("Strawberry", R.drawable.ic_launcher_background);
fruitList.add(strawberry);
Fruit cherry = new Fruit("Cherry", R.drawable.ic_launcher_background);
fruitList.add(cherry);
Fruit mango = new Fruit("Mango", R.drawable.ic_launcher_background);
fruitList.add(mango);
}
}
三、RecyclerView的常用方法
- addItemDecoration();//添加Item的樣式
- computeVerticalScrollRange();//獲取Recycler內(nèi)容高度
- getAdapter().getItemCount();//獲得Adapter中Item總個(gè)數(shù)
- getChildCout();//獲取RecyclerView可見(jiàn)Item個(gè)數(shù)
- smoothScrollToPosition(0);//將某個(gè)位置的Item滑動(dòng)到頂部(有滾動(dòng)效果,平滑動(dòng)畫(huà),適用于列表數(shù)量不多的情況)
- scrollToPositionWithOffset(0,0);//將某個(gè)位置的Item滑動(dòng)到頂部(無(wú)動(dòng)畫(huà),不平滑)
四、給整個(gè)Item設(shè)置點(diǎn)擊事件(待補(bǔ)充)
因?yàn)镽ecyclerView沒(méi)有對(duì)整個(gè)Item設(shè)置點(diǎn)擊事件的方法,要想對(duì)整個(gè)Item設(shè)置點(diǎn)擊事件需要在Adapter里面寫(xiě)一個(gè)回調(diào)方法。(之后補(bǔ)充)
五、給Item設(shè)置分割和點(diǎn)擊樣式(待補(bǔ)充)
ScrollView
一、什么是ScrollView
視圖的滾動(dòng)過(guò)程,其實(shí)是在不斷修改原點(diǎn)坐標(biāo)。當(dāng)手指觸摸后,ScrollView
會(huì)暫時(shí)攔截觸摸事件,使用一個(gè)計(jì)時(shí)器。假如在計(jì)時(shí)器到點(diǎn)后沒(méi)有發(fā)生手指移動(dòng)事件,那么ScrollView
發(fā)送tracking events到被點(diǎn)擊的subView;若是在計(jì)時(shí)器到點(diǎn)后發(fā)生了移動(dòng)事件,那么ScrollView
取消tracking自己促發(fā)滾動(dòng)。
二、ScrollView的用法
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ListViewActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
-
HorizontalScrollView
:水平滑動(dòng)。只需將ScrollView替換為HorizontalScrollView,LinearLayout的方向改變?yōu)関ertical。 - 注意:
ScrollView
的子元素只能有一個(gè),所以得增加一個(gè)LinearLayout布局,把其他控件放在這個(gè)LinearLayout中,那么ScrollViewd的子元素就只有一個(gè)LinearLayout了,而LinearLayout的子元素不限制。
三、ScrollView的屬性
- android:scrollbars:設(shè)置滾動(dòng)條顯示。none(隱藏),horizontal(水平),vertical(垂直)。
- android:scrollbarFadeDuration:設(shè)置滾動(dòng)條淡出效果(從有到慢慢的變淡直至消失)時(shí)間,以毫秒為單位。Android2.2中滾動(dòng)條滾動(dòng)完之后會(huì)消失,再滾動(dòng)又會(huì)出來(lái),在1.5、1.6版本里面會(huì)一直顯示著。
- android:scrollbarSize:設(shè)置滾動(dòng)條的寬度。
- android:scrollbarStyle:設(shè)置滾動(dòng)條的風(fēng)格和位置。設(shè)置值:insideOverlay、insideInset、outsideOverlay、outsideInset
- android:scrollbarThumbHorizontal:設(shè)置水平滾動(dòng)條的drawable。
- android:scrollbarThumbVertical:設(shè)置垂直滾動(dòng)條的drawable.
- android:scrollbarTrackHorizontal:設(shè)置水平滾動(dòng)條背景(軌跡)的色drawable
- android:soundEffectsEnabled:設(shè)置點(diǎn)擊或觸摸時(shí)是否有聲音效果
四、ScrollView嵌套ListView的滑動(dòng)沖突
- 當(dāng)ListView放入ScrollView后,ListView的數(shù)據(jù)就只能顯示一行,嚴(yán)重影響使用體驗(yàn)。
- 原因是scrollView中的ListView在計(jì)算高度時(shí)跳過(guò)了
measureHeightOfChildren
方法的,只計(jì)算了第一個(gè)item的高度,因而只會(huì)顯示一條數(shù)據(jù)的高度。 - 解決辦法:自定義一個(gè)ExpandingListView 繼承Listview,然后重寫(xiě)
onMeasure
方法。
public class ExpandingListView extends ListView {
public ExpandingListView(Context context) {
super(context);
}
public ExpandingListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ExpandingListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
//重寫(xiě)OnMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
注意:GridView的滑動(dòng)沖突同理
五、ScrollView嵌套R(shí)ecyclerView的滑動(dòng)沖突
recyclerView.setLayoutManager(new LinearLayoutManager(this){
@Override
public boolean canScrollVertically() {
//解決ScrollView里存在多個(gè)RecyclerView時(shí)滑動(dòng)卡頓的問(wèn)題
//如果你的RecyclerView是水平滑動(dòng)的話可以重寫(xiě)canScrollHorizontally方法
return false;
}
});
//解決數(shù)據(jù)加載不完的問(wèn)題
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(true);
//解決數(shù)據(jù)加載完成后, 沒(méi)有停留在頂部的問(wèn)題
recyclerView.setFocusable(false);
使用了上面的方法還無(wú)法解決就把布局中的RecyclerView外層的ScrollView換成NestedScrollView就可以解決了
六、ScrollView嵌套EditView、TextView的滑動(dòng)沖突
1、Activity中設(shè)置共同的滑動(dòng)監(jiān)聽(tīng)
private OnTouchListener touchListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN
|| event.getAction() == MotionEvent.ACTION_MOVE){
//按下或滑動(dòng)時(shí)請(qǐng)求父節(jié)點(diǎn)不攔截子節(jié)點(diǎn)
v.getParent().requestDisallowInterceptTouchEvent(true);
}
if(event.getAction() == MotionEvent.ACTION_UP){
//抬起時(shí)請(qǐng)求父節(jié)點(diǎn)攔截子節(jié)點(diǎn)
v.getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
}
};
2、EditText和TextView對(duì)象調(diào)用該事件
editText.setOnTouchListener(touchListener);
textView.setOnTouchListener(touchListener);
//textView單獨(dú)設(shè)置滑動(dòng)方法
textView.setMovementMethod(ScrollingMovementMethod.getInstance());
3、XML滑動(dòng)條設(shè)置
android:scrollbars="vertical"
android:scrollbarStyle="outsideOverlay"