一、前言
最近的课,需要用ViewPager结合Fragment,仿照QQ相册做一个简单小相册,包括照片切换、点赞、评论和查看评论等小功能。其中,滑动切换图片是新内容,同时结合其他几个组件回顾一下前面所学。
ViewPage,主要作用是左右切换当前的view,实现滑动切换的效果,开始动手之后才发现,ViewPager的两个适配器FragmentPagerAdapter和FragmentStatePagerAdapter都被谷歌弃用了,故此在网上查了下平替,就看到了ViewPager2。
图1:被弃用了的好哥俩
在网上查了下,查到的结果是ViewPager2作为ViewPager平替,ViewPager2各方面都有优化,这里就不展开了。那么我们来看看本项目我们用到的相关的各类方法:
表1:ViewPager2相关的方法
布局 | ViewPager2 |
适配器 | FragmentStateAdapter |
监听 | OnPageChangeCallback |
实现方法 | onPageScrolled: 当前页面开始滑动时 onPageSelected: 当页面被选中时 onPageScrollStateChanged: 当前页面滑动状态变动时 |
二、成果
先看看最终效果
图2:简单小相册成品效果
三、代码
1.布局:
先是主布局:
<?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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioGroup
android:id="@+id/RadioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">
<RadioButton
android:id="@+id/radioButton1"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_weight="1"
android:background="@drawable/button_selector"
android:button="@null" />
<RadioButton
android:id="@+id/radioButton2"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_weight="1"
android:background="@drawable/button_selector"
android:button="@null" />
<RadioButton
android:id="@+id/radioButton3"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_weight="3"
android:background="@drawable/button_selector"
android:button="@null" />
<RadioButton
android:id="@+id/radioButton4"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_weight="3"
android:background="@drawable/button_selector"
android:button="@null" />
</RadioGroup>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="10">
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="评论" />
<ImageView
android:id="@+id/dianzan"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="3"
android:src="@drawable/zan" />
<ImageView
android:id="@+id/pinglun"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="3"
android:src="@drawable/pl" />
</LinearLayout>
</LinearLayout>
再到Fragment_1~Fragment_4(用不同图片):
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context=".Fragment1">
<ImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@drawable/s1" />
</LinearLayout>
最后回顾前面活动跳转的内容,点查看评论弹出一个对话框格式的活动:
<?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=".PlActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="评论回复(2)" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginRight="5dp"
android:scaleType="centerCrop"
android:src="@drawable/tx1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="GG Bond" />
<TextView
android:id="@+id/time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="2023年4月18日 12:12" />
<TextView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="666美美美。" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv2"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginRight="5dp"
android:scaleType="centerCrop"
android:src="@drawable/tx2" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/title2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="JJ Bond" />
<TextView
android:id="@+id/time2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="2023年4月18日 12:15" />
<TextView
android:id="@+id/content2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="666美美美。" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
最后还要在manifests修改一下活动的主题,把评论的布局变成一个对话框样式:
<activity
android:name=".PlActivity"
android:theme="@style/Theme.AppCompat.Dialog.MinWidth"
android:exported="false" />
2.后台
先自定义一个适配器:
package com.example.hsn_0320;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.ArrayList;
import java.util.List;
public class MyFragmentPageAdapter extends FragmentStateAdapter {
private List<Fragment> fragmentList1 = new ArrayList<>();
public MyFragmentPageAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<Fragment> fragmentList) {
super(fragmentManager, lifecycle);
this.fragmentList1 = fragmentList;
}
@NonNull
@Override
public Fragment createFragment(int position) {
//用来根据position创建fragment
return fragmentList1.get(position);
}
@Override
public int getItemCount() {
//返回Item的数量
return fragmentList1 == null ? 0 : fragmentList1.size();
}
}
再到主活动:
package com.example.hsn_0320;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.widget.ViewPager2;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener, RadioGroup.OnCheckedChangeListener {
private ViewPager2 mViewPager2;
private ArrayList<Fragment> mFragment;
private MyFragmentPageAdapter myAdapter;
private ImageView dianzan, pinglun;
private boolean dianzanflag = true;
private RadioGroup mRadioGroup;
private List<Integer> mTabs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
initAdapter();
dianzan = findViewById(R.id.dianzan);
pinglun = findViewById(R.id.pinglun);
dianzan.setOnClickListener(this);
pinglun.setOnClickListener(this);
}
private void initAdapter() {
//分别是获取碎片管理器,获取生命周期,对应的Fragment
myAdapter = new MyFragmentPageAdapter(getSupportFragmentManager(), getLifecycle(), mFragment);
mViewPager2.setAdapter(myAdapter);//设置适配器
}
private void initData() {
//碎片初始化
mFragment = new ArrayList<>();
mFragment.add(new Fragment1());
mFragment.add(new Fragment2());
mFragment.add(new Fragment3());
mFragment.add(new Fragment4());
//对应的radioButton初始化
mTabs = new ArrayList<>();
mTabs.add(R.id.radioButton1);
mTabs.add(R.id.radioButton2);
mTabs.add(R.id.radioButton3);
mTabs.add(R.id.radioButton4);
mRadioGroup.check(R.id.radioButton1);
}
private void initView() {
mViewPager2 = findViewById(R.id.vp);
//我们看了源码,里面还没interface接口方法,这里只能用了内部类方式重写实现方法
mViewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
//当页面选取了第i张时候,按钮也check到第i个
mRadioGroup.check(mTabs.get(position));
}
});
mRadioGroup = findViewById(R.id.RadioGroup);
mRadioGroup.setOnCheckedChangeListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.dianzan:
dianzan.setSelected(dianzanflag);
dianzanflag = !dianzanflag;
/*
比如,按下第一次之后,从true变成了false;
第二次之后,又从false变成了true,
点赞和取消点赞就这样完成啦
*/
break;
case R.id.pinglun:
Intent mI = new Intent(MainActivity.this, PlActivity.class);
startActivity(mI);
break;
}
}
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
//对应前面,当按钮check第i个的时候,图片需要设置到第i项
mViewPager2.setCurrentItem(mTabs.indexOf(checkedId));
}
}
而相册碎片Fragment_1~Fragment_4和评论PlActivity,后台都没添加逻辑,也不展示啦。
3.相关资源
按钮资源(第一个是seletor,第二个是选中时候变色,第三个是未选择的颜色,就懒得分开了):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/button_check" android:state_checked="true" />
<item android:drawable="@drawable/button_checkoff" />
</selector>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:useLevel="true">
<solid android:color="#2196F3" />
<stroke
android:width="1dp"
android:color="#3F51B5" />
<size
android:width="30dp"
android:height="30dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:useLevel="true">
<solid android:color="#FF9800" />
<stroke
android:width="1dp"
android:color="#2196F3" />
<size
android:width="30dp"
android:height="30dp" />
</shape>
再加上点赞的资源(用了PPT里的图标哈,还可以变色,图就不放了,放个selector):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/zan_off" android:state_selected="false" />
<item android:drawable="@drawable/zan_on" android:state_selected="true" />
</selector>
四、后续
可以看到,目前评论内容也是定死在了前台布局,后续再把数据库学完后,再结合Listview等,逐渐形成一个更“像样”的模块