Android Java 实现轮播
创建适配器 ImageAdapter
ImageAdapter 用于将数据(轮播图)绑定到 ViewPage2上。
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.viewpage.two.fragment.ImageFragment;
import java.util.List;
public class ImageAdapter extends FragmentStateAdapter {
private List<String> imageUrls;
public ImageAdapter(@NonNull FragmentActivity fragmentActivity, List<String> imageUrls) {
super(fragmentActivity);
this.imageUrls = imageUrls;
}
@NonNull
@Override
public Fragment createFragment(int position) {
// 图片集合大小
int imageUrlSize = imageUrls.size();
// 创建一个包含图片的Fragment实例
return ImageFragment.newInstance(imageUrls.get(position % imageUrlSize));
}
@Override
public int getItemCount() {
//return imageUrls.size();
return Integer.MAX_VALUE;// 无限循环滚动
}
}
添加 glide 依赖
dependencies {
......
implementation("com.github.bumptech.glide:glide:4.15.1")
}
创建 ImageFragment
用于显示每一张图片。
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
public class ImageFragment extends Fragment {
private String imageUrl;
public static ImageFragment newInstance(String imageUrl) {
ImageFragment fragment = new ImageFragment();
Bundle args = new Bundle();
args.putString("imageUrl", imageUrl);
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 初始化并返回包含ImageView的View
ImageView imageView = new ImageView(getContext());
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
imageView.setLayoutParams(layoutParams);
// 加载图片
Glide.with(this).load(imageUrl).into(imageView);
return imageView;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
imageUrl = getArguments().getString("imageUrl");
}
}
}
创建布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".activity.MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="@android:color/holo_purple"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/indicatorContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="@+id/viewPager"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
展示轮播图
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import com.viewpage.two.R;
import com.viewpage.two.adapter.ImageAdapter;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager;//轮播图组件
private LinearLayout indicatorContainer;//指示器容器
private List<String> imageUrls;//要加载的网络图片集合
private int preIndicatorIndex = 0;//当前指示器索引
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.viewPager);
indicatorContainer = findViewById(R.id.indicatorContainer);
imageUrls = getImageUrls(); // 获取图片链接列表
initViewPager();
initIndicator();
}
private void initViewPager() {
ImageAdapter adapter = new ImageAdapter(this, imageUrls);
viewPager.setAdapter(adapter);
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
// 图片集合大小
int imageUrlSize = imageUrls.size();
// 根据上一次ViewPage的索引修改指示器状态
indicatorContainer.getChildAt(preIndicatorIndex % imageUrlSize).setSelected(false);
// 根据ViewPage当前索引修改指示器状态
indicatorContainer.getChildAt(position % imageUrlSize).setSelected(true);
// 保持当前ViewPage索引
preIndicatorIndex = position;
}
});
}
// 绑定指示器
private void initIndicator() {
// 添加指示点
for (int i = 0; i < imageUrls.size(); i++) {
View indicator = new View(this);
// 指示点选中与非选中状态的drawable
indicator.setBackgroundResource(R.drawable.selector_indicator);
indicator.setLayoutParams(new LinearLayout.LayoutParams(50, 50));
indicatorContainer.addView(indicator);
}
}
List<String> getImageUrls() {
List<String> list = new ArrayList<>();
list.add("https://photo.zastatic.com/images/photo/272596/1090382741/3908457282187447162.png");
list.add("https://photo.zastatic.com/images/photo/272596/1090382741/142465111773882534.png");
list.add("https://photo.zastatic.com/images/photo/272596/1090382741/144651611773882078.png");
return list;
}
}
预览 轮播图
Android Kotlin 实现轮播
创建适配器 ImageAdapter
ImageAdapter 用于将数据(轮播图)绑定到 ViewPage2上。
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.kotlin.viewpage.fragment.ImageFragment
class ImageAdapter(fragmentActivity: FragmentActivity, private val imageUrls: List<String>) :
FragmentStateAdapter(fragmentActivity) {
override fun createFragment(position: Int): Fragment {
// 图片集合大小
val imageUrlSize = imageUrls.size
// 创建一个包含图片的Fragment实例
return ImageFragment.newInstance(imageUrls[position % imageUrlSize])
}
override fun getItemCount(): Int {
//return imageUrls.size();
return Int.MAX_VALUE // 无限循环滚动
}
}
添加 glide 依赖
创建 ImageFragment
用于显示每一张图片。
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
class ImageFragment : Fragment() {
private var imageUrl: String? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// 初始化并返回包含ImageView的View
val imageView = ImageView(context)
imageView.scaleType = ImageView.ScaleType.CENTER_CROP
val layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
imageView.layoutParams = layoutParams
// 加载图片
Glide.with(this).load(imageUrl).into(imageView)
return imageView
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (arguments != null) {
imageUrl = requireArguments().getString("imageUrl")
}
}
companion object {
fun newInstance(imageUrl: String?): ImageFragment {
val fragment = ImageFragment()
val args = Bundle()
args.putString("imageUrl", imageUrl)
fragment.arguments = args
return fragment
}
}
}
创建布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".activity.MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="@android:color/holo_purple"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/indicatorContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="@+id/viewPager"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"></LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
展示轮播图
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
import com.kotlin.viewpage.R
import com.kotlin.viewpage.adapter.ImageAdapter
class MainActivity : AppCompatActivity() {
private var viewPager: ViewPager2? = null //轮播图组件
private var indicatorContainer: LinearLayout? = null //指示器容器
private var imageUrls: List<String>? = null //要加载的网络图片集合
private var preIndicatorIndex = 0 //当前指示器索引
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewPager = findViewById(R.id.viewPager)
indicatorContainer = findViewById(R.id.indicatorContainer)
imageUrls = getImageUrls() // 获取图片链接列表
initViewPager()
initIndicator()
}
private fun initViewPager() {
val adapter = imageUrls?.let { ImageAdapter(this, it) }
viewPager!!.adapter = adapter
viewPager!!.registerOnPageChangeCallback(object : OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
// 图片集合大小
val imageUrlSize = imageUrls!!.size
// 根据上一次ViewPage的索引修改指示器状态
indicatorContainer!!.getChildAt(preIndicatorIndex % imageUrlSize).isSelected = false
// 根据ViewPage当前索引修改指示器状态
indicatorContainer!!.getChildAt(position % imageUrlSize).isSelected = true
// 保持当前ViewPage索引
preIndicatorIndex = position
}
})
}
// 绑定指示器
private fun initIndicator() {
// 添加指示点
for (i in imageUrls!!.indices) {
val indicator = View(this)
// 指示点选中与非选中状态的drawable
indicator.setBackgroundResource(R.drawable.selector_indicator)
indicator.layoutParams = LinearLayout.LayoutParams(50, 50)
indicatorContainer!!.addView(indicator)
}
}
private fun getImageUrls(): List<String> {
val list: MutableList<String> = ArrayList()
list.add("https://photo.zastatic.com/images/photo/272596/1090382741/3908457282187447162.png")
list.add("https://photo.zastatic.com/images/photo/272596/1090382741/142465111773882534.png")
list.add("https://photo.zastatic.com/images/photo/272596/1090382741/144651611773882078.png")
return list
}
}
预览 轮播图
Andoid Compose 实现轮播
导入依赖包
dependencies {
......
implementation ("androidx.activity:activity-compose:1.3.1")
implementation("androidx.compose.material:material:1.4.3")
implementation("androidx.compose.ui:ui-tooling:1.4.3")
}
启用Compose
Compose自定义轮播图
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
LineIndicatorExample()
}
}
@OptIn(ExperimentalFoundationApi::class)
@Preview
@Composable
fun LineIndicatorExample() {
val list = mutableListOf<Int>()
list.add(R.drawable.image1)
list.add(R.drawable.image2)
list.add(R.drawable.image3)
Box(modifier = Modifier.fillMaxWidth()) {
val pageCount = list.size
// 初始化页面
val pagerState = rememberPagerState(initialPage = 0)
// 滚到当前页面(实现了无限循环滚动)
val pageCountIndex = remember {
derivedStateOf {
(pagerState.currentPage - Int.MAX_VALUE / 2).floorMod(list.size)
}
}
HorizontalPager(
pageCount = Int.MAX_VALUE,//当前页面数量(方便实现无限循环滚动)
beyondBoundsPageCount = 2,//当前页面前后预加载的页面数量
state = pagerState
) { page ->
Image(
painter = painterResource(id = list[page % pageCount]),
modifier = Modifier
.fillMaxWidth()
.height(220.dp),
contentDescription = "img",
contentScale = ContentScale.Crop
)
}
Row(
Modifier
.height(24.dp)
.fillMaxWidth()
.background(Color.Yellow)
.align(Alignment.BottomCenter),
horizontalArrangement = Arrangement.Center,//水平居中
verticalAlignment = Alignment.CenterVertically,//垂直居中
) {
repeat(pageCount) { iteration ->
val color = if (pageCountIndex.value == iteration) {
Color.Red
} else {
Color.Red.copy(alpha = 0.3f)
}
Box(
modifier = Modifier
.padding(4.dp)//指示器之间的距离
.clip(RoundedCornerShape(4.dp))
.background(color)
.width(8.dp)
.height(8.dp)
)
}
}
}
}
private fun Int.floorMod(other: Int): Int = when (other) {
0 -> this
else -> this - floorDiv(other) * other
}
}
预览效果
IOS Object-c 轮播图 参考 博客园 参考 githunb
自定义 CarouseView
用于显示轮播图。
展示轮播图
预览轮播图
IOS Swift 轮播图 Object-c转Swift
自定义 CarouseView
用于显示轮播图。
展示轮播图
预览轮播图
Flutter 轮播图
引入card_swiper 插件
实现轮播图
// 轮播图
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// 定义轮播图列表
List<Widget> imgList = [];
// 记录一下当前图片的索引,激活指示器背景色
var curIndex = 0;
final PageController _pageController = PageController(initialPage: 1);
var imgUrls = [ "https://photo.zastatic.com/images/photo/272596/1090382741/3908457282187447162.png", "https://photo.zastatic.com/images/photo/272596/1090382741/142465111773882534.png", "https://photo.zastatic.com/images/photo/272596/1090382741/144651611773882078.png" ];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('轮播图'),
backgroundColor: Colors.blue,
),
body: SizedBox(
height: 200,
child: Swiper(
itemBuilder: (BuildContext context, int index) {
return Container(
color: Colors.blue.withOpacity(0.2),
width: double.infinity,
height: double.infinity,
child: Image.network(
imgUrls[index],
fit: BoxFit.cover,
),
);
},
onTap: (index) {
if (kDebugMode) {
print(index);
}
},
itemCount: imgUrls.length,
autoplay: true,
pagination: const SwiperPagination(
builder: DotSwiperPaginationBuilder(
color: Color(0xFFFFFFFF),
activeColor: Color(0xFFFF4646))),
// control: const SwiperControl(),//< >
)));
}
}
预览轮播图
鸿蒙 轮播图 参考 OpenHarmonyOS Swiper
@Entry
@Component
struct Index {
private swiperController: SwiperController = new SwiperController();
private swiperData: string[] = [
'https://photo.zastatic.com/images/photo/272596/1090382741/3908457282187447162.png',
'https://photo.zastatic.com/images/photo/272596/1090382741/142465111773882534.png',
'https://photo.zastatic.com/images/photo/272596/1090382741/144651611773882078.png',
];
build() {
Column() {
Swiper(this.swiperController) {
ForEach(this.swiperData, (item: string) => {
//内容区
Image(item)
.width('100%')
.height(150)
.borderRadius(10)
.onClick(() => {
console.log("图片被点击了",item)
})
})
}
.margin({ top: 10 })
.width('95%')
.loop(true)
.autoPlay(true)
// 指示器样式
.indicatorStyle({
selectedColor: Color.Red,
bottom: 10,
})
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
ReactNative 轮播图
安装Swiper
npm install react-native-swiper --save
自定义 SwiperComponent 组件
import React, {useEffect} from 'react';
import {View, Image, StyleSheet, TouchableOpacity} from 'react-native';
import Swiper from 'react-native-swiper';
import {pxToPd} from './device';
const SlideItem = ({item, onClick}) => {
return (
<View style={styles.slide}>
<TouchableOpacity
style={styles.touchImage}>
<Image source={{uri: item.image}} style={styles.image} />
</TouchableOpacity>
</View>
);
};
function SwiperComponent({items}) {
useEffect(() => {
return () => {};
}, []);
return (
<View style={styles.container}>
<Swiper
style={styles.wrapper}
autoplay={true}
observer= {true}
observeParents={true}
dotStyle={styles.dot}
horizontal={true}
activeDotStyle={styles.activeDot}>
{items.map((item, index) => (
<SlideItem key={index} item={item}/>
))}
</Swiper>
</View>
);
}
const styles = StyleSheet.create({
container: {
width: '100%',
height: pxToPd(400),
},
wrapper: {},
dot: {
backgroundColor: '#999',
},
activeDot: {
backgroundColor: '#eb5747',
},
slide: {
flex: 1,
},
image: {
borderRadius: pxToPd(24),
width: '93.6%',
height: '100%',
resizeMode: 'cover',
},
touchImage: {
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
});
export default SwiperComponent;
创建轮播图
import React, { useState,} from 'react';
import {AppRegistry,View,} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
// 轮播图
import SwiperComponent from './SwiperComponent';
const Swiper = () => {
//轮播图
const [banner, setBanner] = useState([
{
image:"https://photo.zastatic.com/images/photo/272596/1090382741/3908457282187447162.png",
isClick: true,
},
{
image:"https://photo.zastatic.com/images/photo/272596/1090382741/142465111773882534.png",
isClick: false,
},
{
image:"https://photo.zastatic.com/images/photo/272596/1090382741/144651611773882078.png",
isClick: false,
},
]);
return (
<View>
<SwiperComponent items={banner} />
</View>
);
};
AppRegistry.registerComponent(appName, () => Swiper);
预览轮播图
轮播图案例
切换到分支 picture_carousel_2024_06_02