Android Banner
Posted 真菜啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Banner相关的知识,希望对你有一定的参考价值。
前面写了使用ViewPager和ViewPager2实现Banner的方式,今天来用Compose实现一下。
Compose相对于前两种,优势极其明显,就两个字简单!简单!还是他妈的简单
话不多说,上代码。
引入依赖
implementation("androidx.compose.foundation:foundation:1.4.3")
implementation("androidx.compose.foundation:foundation-layout:1.4.3")
版本匹配
当前最新的compose版本匹配kotlin的1.8.10,所以需要修改下项目根目录下的build.gradle文件和模块下的build.gradle文件
根目录下的build.gradle
plugins
id \'com.android.application\' version \'7.4.2\' apply false
id \'com.android.library\' version \'7.4.2\' apply false
id \'org.jetbrains.kotlin.android\' version \'1.8.10\' apply false
模块下的build.gradle文件
android
// ...
compileOptions
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
kotlinOptions
jvmTarget = \'1.8\'
buildFeatures
compose true
composeOptions
kotlinCompilerExtensionVersion \'1.4.3\'
packagingOptions
resources
excludes += \'/META-INF/AL2.0,LGPL2.1\'
代码实现
class MainActivity : ComponentActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContent
BannerTheme
// A surface container using the \'background\' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
)
Banner(bannerItems = DataStore.getBanner())
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Banner(bannerItems: List<BannerItem>)
val pagerState = rememberPagerState()
HorizontalPager(
pageCount = bannerItems.size,
state = pagerState,
modifier = Modifier
.height(180.dp)
.fillMaxWidth()
.padding(16.dp)
) index ->
BannerItem(bannerItems[index])
@Composable
fun BannerItem(banner: BannerItem)
Card(
modifier = Modifier
.fillMaxWidth()
.height(180.dp)
.clip(RoundedCornerShape(16.dp))
.padding(8.dp)
)
Image(
painter = painterResource(id = banner.id),
contentDescription = banner.desc,
contentScale = ContentScale.FillWidth
)
完成,so easy!!!
Android三方框架banner实现轮播图
Android三方框架banner实现轮播图
关于
本篇使用的是基于viewpager2的一个开源banner,性能、生命周期都有保障,就是有一点小的功能需要我们自己去修改。本篇也是作为简易音乐博客系列之一。
效果图
第一步,添加引用
在工程build下添加仓库maven:
allprojects {
repositories {
google()
jcenter()
maven { url "https://s01.oss.sonatype.org/content/groups/public" }
}
}
在项目build下添加banner和viewpager2的引用:
implementation 'io.github.youth5201314:banner:2.2.2'
implementation "androidx.viewpager2:viewpager2:1.0.0"
第二步,新增实体类及测试数据
public class DataBean implements Serializable {
public String imageUrl;
public String title;
public String url;
public DataBean(String imageUrl, String title) {
this.imageUrl = imageUrl;
this.title = title;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public void setTitle(String title) {
this.title = title;
}
public String getImageUrl() {
return imageUrl;
}
public String getTitle() {
return title;
}
public static List<DataBean> getTestData() {
List<DataBean> list = new ArrayList<>();
list.add(new DataBean("https://dfzximg02.dftoutiao.com/news/20210401/20210401222253_acbd3f414dc150c4cf25d91dcac0cf36_1_mwpm_03201609.jpeg", "标题0" ));
list.add(new DataBean("https://dfzximg02.dftoutiao.com/news/20210401/20210401222253_acbd3f414dc150c4cf25d91dcac0cf36_2_mwpm_03201609.jpeg", "标题1" ));
list.add(new DataBean("https://dfzximg02.dftoutiao.com/news/20210401/20210401221040_d2957dc25d3878b4fdf0816289cde4fd_1_mwpm_03201609.png", "标题2"));
list.add(new DataBean("http://cn.bing.com/th?id=OHR.FooledYa_EN-CN7497696381_1920x1080.jpg", "标题3"));
list.add(new DataBean("https://dfzximg02.dftoutiao.com/news/20210401/20210401222006_3a2f89e1dbaa16f8a7f7754e00d8bf77_1_mwpm_03201609.jpeg", "标题4"));
return list;
}
}
第三步,添加banner实例控件,修改主界面代码
修改主界面布局文件:
<?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"
android:orientation="vertical"
tools:context=".MainActivity">
<com.youth.banner.Banner
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="160dp"
android:layout_marginStart="15dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="15dp" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="跳转页面"
/>
</LinearLayout>
修改MainActivity.java
,简单使用banner轮播功能:
public class MainActivity extends AppCompatActivity {
Banner banner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initView() {
findViewById(R.id.button).setOnClickListener(v -> {
Intent intent = new Intent(this,Main2Activity.class);
startActivity(intent);
});
banner = findViewById(R.id.banner);
}
private void initData() {
//banner自带图片轮播的适配器
banner.setAdapter(new BannerImageAdapter<DataBean>(DataBean.getTestData()) {
@Override
public void onBindView(BannerImageHolder holder, DataBean data, int position, int size) {
Glide.with(holder.imageView)
.load(data.imageUrl)
.thumbnail(Glide.with(holder.itemView).load(R.drawable.loading))//加载成功前显示一个loading的加载
//.apply(RequestOptions.bitmapTransform(new RoundedCorners(30))) //设置图片圆角
.into(holder.imageView);
//关于glide的引用添加:
//implementation 'com.github.bumptech.glide:glide:4.11.0'
//annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}
}).addBannerLifecycleObserver(this)//添加生命周期观察者
.setIntercept(false) //是否要拦截事件
.setBannerRound(10f) //圆角
.setIndicator(new CircleIndicator(this)) //圆形指示器 还支持条形指示器等
.setOnBannerListener(new OnBannerListener() {
@Override
public void OnBannerClick(Object data, int position) {
Toast.makeText(MainActivity.this,"位置"+position+"",Toast.LENGTH_SHORT).show();
}
}) ;
}
}
自定义图片+标题轮播图
到这,基本的轮播功能已经实现了,但是很多轮播图可能还需要有标题,即图片+标题,就要自己编写适配器继承BannerAdapter
,首先编写一个banner_title_image.xml
的布局文件(就是一个简单的图片加标题):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/bannerImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/bannerTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center_vertical"
android:paddingRight="5dp"
android:paddingBottom="1dp"
android:singleLine="true"
android:textColor="#ffffff"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
第二步,编写TitleHolder
继承ViewHolder:
public class TitleHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public TextView textView;
public TitleHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.bannerImage);
textView = itemView.findViewById(R.id.bannerTitle);
}
}
第三步,编写ImageTitleAdapter
继承banner三方提供的BannerAdapter:
/**
* banner轮播图适配器 图片+标题
*/
public class ImageTitleAdapter extends BannerAdapter<DataBean,TitleHolder> {
public ImageTitleAdapter(List<DataBean> datas) {
super(datas);
}
@Override
public TitleHolder onCreateHolder(ViewGroup parent, int viewType) {
return new TitleHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.banner_title_image,parent,false));
}
@Override
public void onBindView(TitleHolder holder, DataBean data, int position, int size) {
Glide.with(holder.imageView)
.load(data.imageUrl)
.thumbnail(Glide.with(holder.itemView).load(R.drawable.loading))
.into(holder.imageView);
holder.textView.setText(data.title);
}
}
第四步,修改MainActivity.java
:
private void initData() {
banner.setAdapter(new ImageTitleAdapter(DataBean.getTestData())).addBannerLifecycleObserver(this)//添加生命周期观察者
.setIntercept(false) //是否要拦截事件
.setBannerRound(10f) //圆角
.setIndicator(new RectangleIndicator(this)) //线条指示器
.setIndicatorHeight(5)
.setIndicatorWidth(6,6) //选中下宽度是否一致
.setIndicatorGravity(IndicatorConfig.Direction.CENTER)
.setOnBannerListener(new OnBannerListener() {
@Override
public void OnBannerClick(Object data, int position) {
Toast.makeText(MainActivity.this,"位置"+position+"",Toast.LENGTH_SHORT).show();
}
}) ;
}
效果图
你以为到这里就结束了??
正常情况下使用这个三方轮播图已经结束了,毕竟效果啥的都实现了,但是实际使用中还是发现一些问题,比如在fragment中使用的时候进行fragment切换,再回来就会从头加载轮播,这怎么行,暂时解决办法是在fragmetnt
下(自己选的只能被迫自己解决问题):
//定义一个int保存当前轮播位置
private static int potsition = 0;
@Override
public void onPause() {
super.onPause();
potsition = banner.getViewPager2().getCurrentItem(); //用提供的banner.getCurrentItem()获取不到
}
@Override
public void onResume() {
super.onResume();
if (potsition != 0&&banner !=null){
//从选中位置开始轮播
banner.setStartPosition(potsition);
}
}
补充
后面发型是因为我在母体Activity中通过开启事务后FragmentTransaction.replace()
方法替换fragment(本质上还是调用了remove造成了移除fragment_main碎片,重新新增fragment_main碎片导致fragment_main反复调用onpause->onStop->…onResume()导致的轮播图重新实例化)
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
//切换布局
transaction.replace(R.id.frame_main,fragment);
transaction.commit();
本篇文章到此结束,有问题欢迎批评指正,觉得不错的也请点个赞奥
以上是关于Android Banner的主要内容,如果未能解决你的问题,请参考以下文章