目录
一、登录注册模块
User实体类
public class User {
private String id;
private String password;
public User(){
}
public User(String id,String password){
this.id=id;
this.password=password;
}
public String getId(){
return id;
}
public void setId(String userid){
this.id=userid;
}
public String getPassword(){
return password;
}
public void setPassword(String password){
this.password=password;
}
}
DBOpenHelper类
这部分是登录和注册的数据库逻辑部分,继承了SQLiteOpenHelper,新手不建议上来就连接外部数据库,很容易翻车,先使用Android内部自带的SQLite熟悉一下业务逻辑
public class DBOpenHelper extends SQLiteOpenHelper {
private static final String name="user.db";
private SQLiteDatabase db;
private static SQLiteOpenHelper mInstance;
public DBOpenHelper(Context context){
super(context,name,null,1);
// db=getReadableDatabase();
}
public static synchronized SQLiteOpenHelper getmInstance(Context context){
if(mInstance==null){
mInstance=new DBOpenHelper(context);
}
return mInstance;
}
public static final String usertable="create table " +
"usertable(name varchar(255),password varchar(255))";
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(usertable);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL("drop table if exists usertable");
onCreate(sqLiteDatabase);
}
public long register(User u){
SQLiteDatabase db=getWritableDatabase();
ContentValues cv=new ContentValues();
cv.put("name",u.getId());
cv.put("password",u.getPassword());
db.insert("usertable",null,cv);
long users=db.insert("usertable",null,cv);
return users;
}
public boolean login(String name,String password){
SQLiteDatabase db1=getWritableDatabase();
boolean result=false;
Cursor users=db1.query("usertable",null,"name like ?",new String[]{name},null,null,null);
if(users!=null){
while(users.moveToNext()){
String password1=users.getString(1);
result=password1.equals(password);
return result;
}
}
return false;
}
}
activity_login.xml布局文件
<?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"
android:orientation="vertical">
<!-- tools:context="com.example.homework3.LoginActivity"-->
<ImageView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="50dp"
android:src="@drawable/logo"
/>
<LinearLayout
android:layout_marginTop="100dp"
android:gravity="center_horizontal"
android:layout_width="300dp"
android:layout_height="80dp"
android:layout_marginLeft="50dp"
android:orientation="horizontal" >
<TextView
android:id="@+id/user_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="账号:"
android:layout_weight="1"
android:textColor="#000000"
android:textSize="20sp" />
<EditText
android:id="@+id/username"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:maxLines="1"
android:hint="请输入用户名" />
</LinearLayout>
<LinearLayout
android:layout_width="300dp"
android:layout_height="80dp"
android:layout_marginLeft="50dp"
android:gravity="center_horizontal"
android:orientation="horizontal">
<TextView
android:id="@+id/user_password"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="密 码:"
android:textColor="#000000"
android:textSize="20sp" />
<EditText
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:maxLines="1"
android:inputType="textPassword"
android:hint="请输入密码"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center_horizontal"
android:orientation="horizontal">
<Button
android:id="@+id/btn_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="30dp"
android:paddingRight="30dp"
android:text="登录" />
<Button
android:id="@+id/btn_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="30dp"
android:paddingRight="30dp"
android:text="注册" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="center_horizontal"
>
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/logo2"/>
</LinearLayout>
</LinearLayout>
activity_register.xml布局文件
<?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"
android:orientation="vertical">
<LinearLayout
android:layout_marginTop="100dp"
android:gravity="center_horizontal"
android:layout_width="300dp"
android:layout_height="80dp"
android:layout_marginLeft="50dp"
android:orientation="horizontal" >
<TextView
android:id="@+id/ruser_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="账号:"
android:layout_weight="1"
android:textColor="#000000"
android:textSize="20sp" />
<EditText
android:id="@+id/rusername"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:maxLines="1"
android:hint="请输入用户名" />
</LinearLayout>
<LinearLayout
android:layout_width="300dp"
android:layout_height="80dp"
android:layout_marginLeft="50dp"
android:gravity="center_horizontal"
android:orientation="horizontal">
<TextView
android:id="@+id/ruser_password"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="密 码:"
android:textColor="#000000"
android:textSize="20sp" />
<EditText
android:id="@+id/rpassword"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:maxLines="1"
android:inputType="textPassword"
android:hint="请输入密码"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center_horizontal"
android:orientation="horizontal">
<Button
android:id="@+id/register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="30dp"
android:paddingRight="30dp"
android:onClick="zhuce"
android:text="注册" />
</LinearLayout>
</LinearLayout>
二、主页面
2.1底部导航栏+页面切换的实现
先让Chat老师简单描述下这部分组件的功能
使用了Tablayout+ViewPager2实现底部导航栏以及3个Fragment的页面切换,注意使用ViewPager2时候请务必将android库升级到Androidx,统一库有利于后期统一导入依赖,方便管理
在build.gradle中导入viewPager2和TabLayout依赖
implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation 'com.google.android.material:material:1.2.0-alpha06'
导入依赖之前务必看清文件路径
activity_success.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@+id/tab_layout"
tools:layout_editor_absoluteX="0dp" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="672dp"
android:paddingBottom="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tabBackground="@android:color/transparent"
app:tabIndicatorColor="@android:color/transparent"
app:tabRippleColor="@android:color/transparent" />
</androidx.constraintlayout.widget.ConstraintLayout>
为导航栏和滑动页面设置适配器,这一步很重要,直接复制以下代码就能用了
package zsc.androidstudy.application2;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_DRAGGING;
import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_IDLE;
import static androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_SETTLING;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
//public class TabLayoutMediator {
@RestrictTo(LIBRARY_GROUP)
public final class TabLayoutMediator {
private final @NonNull
TabLayout mTabLayout;
private final @NonNull
ViewPager2 mViewPager;
private final boolean mAutoRefresh;
private final OnConfigureTabCallback mOnConfigureTabCallback;
private RecyclerView.Adapter mAdapter;
private boolean mAttached;
private TabLayoutOnPageChangeCallback mOnPageChangeCallback;
private TabLayout.OnTabSelectedListener mOnTabSelectedListener;
private RecyclerView.AdapterDataObserver mPagerAdapterObserver;
/**
* A callback interface that must be implemented to set the text and styling of newly created
* tabs.
*/
public interface OnConfigureTabCallback {
/**
* Called to configure the tab for the page at the specified position. Typically calls
*
* @param tab The Tab which should be configured to represent the title of the item at the
* given position in the data set.
* @param position The position of the item within the adapter's data set.
*/
void onConfigureTab(@NonNull TabLayout.Tab tab, int position);
}
/**
* Creates a TabLayoutMediator to synchronize a TabLayout and a ViewPager2 together. It will
* update the tabs automatically when the data set of the view pager's adapter changes. The link
* will be established after {@link #attach()} is called.
*
* @param tabLayout The tab bar to link
* @param viewPager The view pager to link
*/
public TabLayoutMediator(@NonNull TabLayout tabLayout, @NonNull ViewPager2 viewPager,
@NonNull OnConfigureTabCallback onConfigureTabCallback) {
this(tabLayout, viewPager, true, onConfigureTabCallback);
}
/**
* Creates a TabLayoutMediator to synchronize a TabLayout and a ViewPager2 together. If {@code
* autoRefresh} is true, it will update the tabs automatically when the data set of the view
* pager's adapter changes. The link will be established after {@link #attach()} is called.
*
* @param tabLayout The tab bar to link
* @param viewPager The view pager to link
* @param autoRefresh If {@code true}, will recreate all tabs when the data set of the view
* pager's adapter changes.
*/
public TabLayoutMediator(@NonNull TabLayout tabLayout, @NonNull ViewPager2 viewPager,
boolean autoRefresh, @NonNull OnConfigureTabCallback onConfigureTabCallback) {
mTabLayout = tabLayout;
mViewPager = viewPager;
mAutoRefresh = autoRefresh;
mOnConfigureTabCallback = onConfigureTabCallback;
}
/**
* Link the TabLayout and the ViewPager2 together.
* adapter.
*/
public void attach() {
if (mAttached) {
throw new IllegalStateException("TabLayoutMediator is already attached");
}
mAdapter = mViewPager.getAdapter();
if (mAdapter == null) {
throw new IllegalStateException("TabLayoutMediator attached before ViewPager2 has an "
+ "adapter");
}
mAttached = true;
// Add our custom OnPageChangeCallback to the ViewPager
mOnPageChangeCallback = new TabLayoutOnPageChangeCallback(mTabLayout);
mViewPager.registerOnPageChangeCallback(mOnPageChangeCallback);
// Now we'll add a tab selected listener to set ViewPager's current item
mOnTabSelectedListener = new ViewPagerOnTabSelectedListener(mViewPager);
mTabLayout.addOnTabSelectedListener(mOnTabSelectedListener);
// Now we'll populate ourselves from the pager adapter, adding an observer if
// autoRefresh is enabled
if (mAutoRefresh) {
// Register our observer on the new adapter
mPagerAdapterObserver = new PagerAdapterObserver();
mAdapter.registerAdapterDataObserver(mPagerAdapterObserver);
}
populateTabsFromPagerAdapter();
// Now update the scroll position to match the ViewPager's current item
mTabLayout.setScrollPosition(mViewPager.getCurrentItem(), 0f, true);
}
/**
* Unlink the TabLayout and the ViewPager
*/
public void detach() {
mAdapter.unregisterAdapterDataObserver(mPagerAdapterObserver);
mTabLayout.removeOnTabSelectedListener(mOnTabSelectedListener);
mViewPager.unregisterOnPageChangeCallback(mOnPageChangeCallback);
mPagerAdapterObserver = null;
mOnTabSelectedListener = null;
mOnPageChangeCallback = null;
}
@SuppressWarnings("WeakerAccess")
void populateTabsFromPagerAdapter() {
mTabLayout.removeAllTabs();
if (mAdapter != null) {
int adapterCount = mAdapter.getItemCount();
for (int i = 0; i < adapterCount; i++) {
TabLayout.Tab tab = mTabLayout.newTab();
mOnConfigureTabCallback.onConfigureTab(tab, i);
mTabLayout.addTab(tab, false);
}
// Make sure we reflect the currently set ViewPager item
if (adapterCount > 0) {
int currItem = mViewPager.getCurrentItem();
if (currItem != mTabLayout.getSelectedTabPosition()) {
mTabLayout.getTabAt(currItem).select();
}
}
}
}
/**
* A {@link ViewPager2.OnPageChangeCallback} class which contains the necessary calls back to
* the provided {@link TabLayout} so that the tab position is kept in sync.
*
* <p>This class stores the provided TabLayout weakly, meaning that you can use {@link
* ViewPager2#registerOnPageChangeCallback(ViewPager2.OnPageChangeCallback)} without removing
* the callback and not cause a leak.
*/
private static class TabLayoutOnPageChangeCallback extends ViewPager2.OnPageChangeCallback {
private final WeakReference<TabLayout> mTabLayoutRef;
private int mPreviousScrollState;
private int mScrollState;
TabLayoutOnPageChangeCallback(TabLayout tabLayout) {
mTabLayoutRef = new WeakReference<>(tabLayout);
reset();
}
@Override
public void onPageScrollStateChanged(final int state) {
mPreviousScrollState = mScrollState;
mScrollState = state;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
TabLayout tabLayout = mTabLayoutRef.get();
if (tabLayout != null) {
// Only update the text selection if we're not settling, or we are settling after
// being dragged
boolean updateText = mScrollState != SCROLL_STATE_SETTLING
|| mPreviousScrollState == SCROLL_STATE_DRAGGING;
// Update the indicator if we're not settling after being idle. This is caused
// from a setCurrentItem() call and will be handled by an animation from
// onPageSelected() instead.
boolean updateIndicator = !(mScrollState == SCROLL_STATE_SETTLING
&& mPreviousScrollState == SCROLL_STATE_IDLE);
setScrollPosition(tabLayout, position, positionOffset, updateText, updateIndicator);
}
}
@Override
public void onPageSelected(final int position) {
TabLayout tabLayout = mTabLayoutRef.get();
if (tabLayout != null
&& tabLayout.getSelectedTabPosition() != position
&& position < tabLayout.getTabCount()) {
// Select the tab, only updating the indicator if we're not being dragged/settled
// (since onPageScrolled will handle that).
boolean updateIndicator = mScrollState == SCROLL_STATE_IDLE
|| (mScrollState == SCROLL_STATE_SETTLING
&& mPreviousScrollState == SCROLL_STATE_IDLE);
selectTab(tabLayout, tabLayout.getTabAt(position), updateIndicator);
}
}
void reset() {
mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
}
}
// region Reflective calls
// Temporarily call methods TabLayout.setScrollPosition(int, float, boolean, boolean) and
// TabLayout.selectTab(TabLayout.Tab, boolean) through reflection, until they have been made
// public in the Material Design Components library.
private static Method sSetScrollPosition;
private static Method sSelectTab;
private static final String SET_SCROLL_POSITION_NAME = "TabLayout.setScrollPosition(int, float,"
+ " boolean, boolean)";
private static final String SELECT_TAB_NAME = "TabLayout.selectTab(TabLayout.Tab, boolean)";
static {
try {
sSetScrollPosition = TabLayout.class.getDeclaredMethod("setScrollPosition", int.class,
float.class, boolean.class, boolean.class);
sSetScrollPosition.setAccessible(true);
sSelectTab = TabLayout.class.getDeclaredMethod("selectTab", TabLayout.Tab.class,
boolean.class);
sSelectTab.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Can't reflect into method TabLayout"
+ ".setScrollPosition(int, float, boolean, boolean)");
}
}
@SuppressWarnings("WeakerAccess")
static void setScrollPosition(TabLayout tabLayout, int position, float positionOffset,
boolean updateSelectedText, boolean updateIndicatorPosition) {
try {
if (sSetScrollPosition != null) {
sSetScrollPosition.invoke(tabLayout, position, positionOffset, updateSelectedText,
updateIndicatorPosition);
} else {
throwMethodNotFound(SET_SCROLL_POSITION_NAME);
}
} catch (Exception e) {
throwInvokeFailed(SET_SCROLL_POSITION_NAME);
}
}
@SuppressWarnings("WeakerAccess")
static void selectTab(TabLayout tabLayout, TabLayout.Tab tab, boolean updateIndicator) {
try {
if (sSelectTab != null) {
sSelectTab.invoke(tabLayout, tab, updateIndicator);
} else {
throwMethodNotFound(SELECT_TAB_NAME);
}
} catch (Exception e) {
throwInvokeFailed(SELECT_TAB_NAME);
}
}
private static void throwMethodNotFound(String method) {
throw new IllegalStateException("Method " + method + " not found");
}
private static void throwInvokeFailed(String method) {
throw new IllegalStateException("Couldn't invoke method " + method);
}
// endregion
/**
* A {@link TabLayout.OnTabSelectedListener} class which contains the necessary calls back to
* the provided {@link ViewPager2} so that the tab position is kept in sync.
*/
private static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener {
private final ViewPager2 mViewPager;
ViewPagerOnTabSelectedListener(ViewPager2 viewPager) {
this.mViewPager = viewPager;
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
mViewPager.setCurrentItem(tab.getPosition(), true);
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
// No-op
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
// No-op
}
}
private class PagerAdapterObserver extends RecyclerView.AdapterDataObserver {
PagerAdapterObserver() {}
@Override
public void onChanged() {
populateTabsFromPagerAdapter();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
populateTabsFromPagerAdapter();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
populateTabsFromPagerAdapter();
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
populateTabsFromPagerAdapter();
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
populateTabsFromPagerAdapter();
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
populateTabsFromPagerAdapter();
}
}
}
//}
设置每个不同页面的Fragment类,一共需要设置三个,这里只列了一个Fragment1类
public class Fragment1 extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private View view;
private RecyclerView recyclerView;
private List<Card> cardList=new ArrayList<>();
private Context context;
public Fragment1() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment Fragment1.
*/
// TODO: Rename and change types and number of parameters
public static Fragment1 newInstance(String param1, String param2) {
Fragment1 fragment = new Fragment1();
return fragment;
}
private void initView(){
recyclerView.setLayoutManager(new LinearLayoutManager(this.getContext(),LinearLayoutManager.VERTICAL,true));
RelationAdapter relationAdapter=new RelationAdapter(this.getActivity(),cardList);
recyclerView.setAdapter(relationAdapter);
}
private void initData(){
String[] nameList=new String[]{"Gargargargarden","Gargargarden","Gargarden","Garden","爱吃烧鸭饭"};
int[] imageList=new int[]{R.drawable.yuehaiguan,R.drawable.jiaotang1,R.drawable.dafosi,R.drawable.shamian,
R.drawable.zhujiangyeyou};
int[] user_imgList=new int[]{R.drawable.tengusan,R.drawable.cat1,R.drawable.cat2,R.drawable.cat3
,R.drawable.cat4};
int length=nameList.length;
for(int i=0;i<length;i++){
cardList.add(new Card(nameList[i],imageList[i],user_imgList[i] ));
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initData();
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view=inflater.inflate(R.layout.fragment_1, container, false);
recyclerView=view.findViewById(R.id.Recycler_view);
initView();
return view;
}
}
Fragment_1.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:context=".Fragment1"
>
<!-- TODO: Update blank fragment layout -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/Recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
设置每一个Tablayout导航栏和ViewPager2滑动对应的Fragment页面
public class MainActivity2 extends AppCompatActivity {
List<Fragment> tabFragmentList = new ArrayList<>();
private int[] tabIcons={
R.drawable.paperplane,
R.drawable.home,
R.drawable.mine
};
private String[] tabs = {"tab1", "tab2", "tab3"};
public static void actionStart(Context context){
Intent intent = new Intent(context, MainActivity2.class);
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_success);
TabLayout tabLayout = findViewById(R.id.tab_layout);
ViewPager2 viewPager = findViewById(R.id.view_pager);
viewPager.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
for(int i=0;i<3;i++){
switch (i){
case 0:
tabFragmentList.add(Fragment1.newInstance("a","b"));
break;
case 1:
tabFragmentList.add(Fragment2.newInstance("c","d"));
break;
case 2:
tabFragmentList.add(Fragment3.newInstance("e","f"));
break;
}
}
viewPager.setAdapter(new FragmentStateAdapter(this) {
@NonNull
@Override
public Fragment createFragment(int position) {
return tabFragmentList.get(position);
}
@Override
public int getItemCount() {
return tabFragmentList.size();
}
});
viewPager.setOffscreenPageLimit(20);
new TabLayoutMediator(tabLayout, viewPager, true, new TabLayoutMediator.OnConfigureTabCallback() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
tab.setIcon(tabIcons[position]);
}
}).attach();
}
}
2.2主页面1
这里使用了RecycleView的线性布局+CardView实现卡片式布局的上下滑动效果,至于为什么是RecyclewView而不是ListView,Chat老师做出以下解释
创建Card实体类
public class Card {
public List<Integer> imageList=new ArrayList<>();
public List<String> nameList=new ArrayList<>();
private String user;
private int imgid;
private int imgint;
public Card(String s, Integer integer, Integer user_imgint) {
this.imgid=integer;
this.user=s;
this.imgint=user_imgint;
}
public int getImageId(){
return imgid;
}
public void setImageId(int id){
imgid=id;
}
public String getName(){
return user;
}
public void setName(String name){
this.user=name;
}
public int getUserImgint(){
return imgint;
}
public void setUserImgint(int userimgint){
imgint=userimgint;
}
}
CardView的布局文件
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="375dp"
android:layout_height="310dp"
android:layout_marginLeft="10dp"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
android:layout_marginTop="50dp"
app:cardCornerRadius="10dp"
app:cardElevation="15dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
>
<!-- 用户名称-->
<TextView
android:id="@+id/user_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="70dp"
android:layout_marginTop="15dp"
android:textSize="15dp"
android:textStyle="bold"
/>
<!-- 用户头像-->
<ImageView
android:id="@+id/user_img"
android:layout_marginLeft="15dp"
android:layout_marginTop="5dp"
android:layout_width="40dp"
android:layout_height="40dp"/>
<ImageView
android:id="@+id/image_card"
android:layout_width="375dp"
android:layout_height="210dp"
android:layout_gravity="center_vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<!--icon-->
<ImageView
android:id="@+id/image_icon1"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginLeft="15dp"
android:src="@drawable/yx_star"
android:layout_marginTop="277dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<ImageView
android:id="@+id/image_icon2"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/back1"
android:layout_marginTop="275dp"
android:layout_marginLeft="50dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.cardview.widget.CardView>
</FrameLayout>
RecycleView和数据,也就是CardView的适配器
public class RelationAdapter extends RecyclerView.Adapter<RelationAdapter.MyHolder> {
private View view;
private Context context;
CardView cv;
ImageView imageView;
ImageView icon1;
ImageView icon2;
TextView name;
ImageView userimg;
private List<Card> myCardList;
public RelationAdapter(Context context,List<Card> cardList){
this.myCardList=cardList;
this.context=context;
}
@NonNull
@Override
public RelationAdapter.MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview,parent,false);
RelationAdapter.MyHolder myHolder=new RelationAdapter.MyHolder(view,this);
myHolder.image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position= myHolder.getAdapterPosition();
Card card=myCardList.get(position);
Toast.makeText(view.getContext(),"用户:"+myCardList.get(position).getName(),
Toast.LENGTH_SHORT).show();
switch (position){
case 0:
Intent intent1=new Intent(view.getContext(),Activity_1.class);
view.getContext().startActivity(intent1);
break;
case 1:
Intent intent2=new Intent(view.getContext(),Activity_2.class);
view.getContext().startActivity(intent2);
break;
case 2:
Intent intent3=new Intent(view.getContext(),Activity_3.class);
view.getContext().startActivity(intent3);
break;
case 3:
Intent intent4=new Intent(view.getContext(),Activity_4.class);
view.getContext().startActivity(intent4);
break;
case 4:
Intent intent5=new Intent(view.getContext(),Activity_5.class);
view.getContext().startActivity(intent5);
break;
}
}
});
return myHolder;
}
@Override
public void onBindViewHolder(@NonNull RelationAdapter.MyHolder holder, int position) {
Log.d("nameList.size是","长度为"+myCardList.size());
holder.image.setImageResource(myCardList.get(position).getImageId());
holder.username.setText(myCardList.get(position).getName());
holder.userimg.setImageResource(myCardList.get(position).getUserImgint());
return;
}
@Override
public int getItemCount() {
return myCardList.size();
}
static class MyHolder extends RecyclerView.ViewHolder{
private CardView card;
private ImageView image;
private ImageView icon1;
private ImageView icon2;
private TextView username;
private ImageView userimg;
private RecyclerView.Adapter adapter;
MyHolder(@NonNull View itemView,RecyclerView.Adapter adapter) {
super(itemView);
this.image=(ImageView) itemView.findViewById(R.id.image_card);
this.userimg=(ImageView)itemView.findViewById(R.id.user_img);
this.username=(TextView)itemView.findViewById(R.id.user_name);
this.adapter=adapter;
}
}
}
再设置图片监听到点击事件后的跳转页面,也就是Activity1
public class Activity_1 extends AppCompatActivity {
private List<Card> cardList=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity1);
}
public static void actionStart(Context context){
Intent intent=new Intent(context,Activity_1.class);
context.startActivity(intent);
}
}
activity_1.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="沿江西路"
android:textSize="30dp"
android:textColor="@color/black"
/>
<ImageView
android:layout_width="375dp"
android:layout_height="210dp"
android:layout_marginTop="70dp"
android:src="@drawable/aiqun"
android:layout_weight="1"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="300dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:textSize="25dp"
android:text="海珠桥和人民桥之间有一条沿江西路,短短两公里藏着这座城市的记忆,广州沿江西路,从沙面岛
到人民桥,再到海珠桥,一路下来,极具西洋特色的复古建筑群,静静地诉说着这座城市的岁月。同时这里也是欣赏珠江两岸风情
和日落最佳位置,碧水蓝天下滤镜都不需要,真的非常好出片!!"
/>
</FrameLayout>
2.3主页面2
同样是RecycleView,也可以上下滑动,实现方法和前面的差不多,只不过这个页面是用了宫格布局
Fragment_2.xml布局文件
<?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=".Fragment2">
<!-- TODO: Update blank fragment layout -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/grid_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
创建Grid类
public class Grid {
private String name;
private int ImageId;
public Grid(String name,int ImageId){
this.name = name;
this.ImageId = ImageId;
}
public int getImageId() {
return ImageId;
}
public void setImageId(int imageId) {
ImageId = imageId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
GridView.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/grid_img"
android:layout_marginTop="30dp"
android:layout_width="195dp"
android:layout_height="260dp"/>
<TextView
android:id="@+id/grid_name"
android:layout_marginTop="260dp"
android:layout_width="100dp"
android:layout_height="30dp"
android:textStyle="bold"
android:textSize="27dp"
android:background="@android:color/background_light"/>
</FrameLayout>
GridAdapter适配器
public class GridAdapter extends RecyclerView.Adapter<GridAdapter.gridHolder> {
private Context context;
private List<Grid> gridList;
public GridAdapter(Context context,List<Grid> gridList){
this.context=context;
this.gridList=gridList;
}
//创建列表组件
@NonNull
@Override
public GridAdapter.gridHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.gridview,null);
GridAdapter.gridHolder gridHolder=new GridAdapter.gridHolder(view,this);
gridHolder.img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position=gridHolder.getAdapterPosition();
Grid grid=gridList.get(position);
switch (position){
case 0:
Intent intent1=new Intent(view.getContext(),Frag2Activity_1.class);
view.getContext().startActivity(intent1);
break;
case 1:
Intent intent2=new Intent(view.getContext(),Frag2Activity_2.class);
view.getContext().startActivity(intent2);
break;
case 2:
Intent intent3=new Intent(view.getContext(),Frag2Activity_3.class);
view.getContext().startActivity(intent3);
break;
case 3:
Intent intent4=new Intent(view.getContext(),Frag2Activity_4.class);
view.getContext().startActivity(intent4);
break;
case 4:
Intent intent5=new Intent(view.getContext(),Frag2Activity_5.class);
view.getContext().startActivity(intent5);
break;
}
}
});
return gridHolder;
}
//绑定数据
@Override
public void onBindViewHolder(@NonNull GridAdapter.gridHolder holder, int position) {
holder.img.setImageResource(gridList.get(position).getImageId());
holder.name.setText(gridList.get(position).getName());
}
@Override
public int getItemCount() {
return gridList.size();
}
public class gridHolder extends RecyclerView.ViewHolder{
TextView name;
ImageView img;
private RecyclerView.Adapter adapter;
public gridHolder(@NonNull View itemView, RecyclerView.Adapter adapter){
super(itemView);
this.name=(TextView) itemView.findViewById(R.id.grid_name);
this.img=(ImageView) itemView.findViewById(R.id.grid_img);
this.adapter=adapter;
}
}
}
设置Fragment2的点击图片监听后的跳转页面,也就是点击图片后进入播放视频的页面
import android.widget.VideoView;
public class Frag2Activity_1 extends AppCompatActivity implements View.OnClickListener {
Button btn_play,btn_replay,btn_pause,btn_stop;
VideoView video;
SeekBar seekBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frag2activity_1);
video=findViewById(R.id.video1);
btn_play=findViewById(R.id.btn_play);
btn_replay=findViewById(R.id.btn_replay);
btn_pause=findViewById(R.id.btn_pause);
btn_stop=findViewById(R.id.btn_stop);
seekBar=findViewById(R.id.seekbar);
btn_play.setOnClickListener(this);
btn_replay.setOnClickListener(this);
btn_pause.setOnClickListener(this);
btn_stop.setOnClickListener(this);
seekBar.setOnSeekBarChangeListener(changeListener);
}
public static void actionStart(Context context){
Intent intent=new Intent(context,Activity_1.class);
context.startActivity(intent);
}
private SeekBar.OnSeekBarChangeListener changeListener=new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress=seekBar.getProgress();
if(video!=null&&video.isPlaying()){
video.seekTo(progress);
}
}
};
private void play(int msec){
Uri uri= Uri.parse("android.resource://"+getPackageName()+"/raw/"+R.raw.guangzhoutower);
String path= uri.toString();
Log.i("Frag2Activity",path);
video.setVideoURI(uri);
video.start();
video.seekTo(msec);
seekBar.setMax(video.getDuration());
//进度条保持刷新
handler.postDelayed(runable,500);
btn_play.setEnabled(false);
video.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
btn_play.setEnabled(true);
}
});
video.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
play(0);
return false;
}
});
}
Handler handler=new Handler();
Runnable runable=new Runnable() {
@Override
public void run() {
int position=video.getCurrentPosition();
int totalduration=video.getDuration();
if(video.isPlaying()){
seekBar.setMax(totalduration);
seekBar.setProgress(position);
}
handler.postDelayed(runable,500);
}
};
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.btn_play:
play(0);
break;
case R.id.btn_replay:
if(video!=null&&video.isPlaying()){
video.seekTo(0);
}
btn_pause.setText("暂停");
play(0);
break;
case R.id.btn_pause:
if(btn_pause.getText().equals("暂停")){
btn_pause.setText("继续");
video.pause();
}else if(btn_pause.getText().equals("继续")){
btn_pause.setText("暂停");
video.start();
}
break;
case R.id.btn_stop:
if(video!=null&&video.isPlaying()){
video.stopPlayback();
btn_play.setEnabled(true);
}
handler.removeCallbacks(runable);
break;
}
}
}
Frag2_Activity1.xml布局文件,这里因为篇幅原因只列了一个,其余的请读者自行创建
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView
android:id="@+id/video1"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<RelativeLayout
android:gravity="center"
android:layout_gravity="bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<SeekBar
android:id="@+id/seekbar"
android:layout_centerHorizontal="true"
android:layout_width="200dp"
android:layout_height="wrap_content"/>
<LinearLayout
android:gravity="center"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btn_play"
android:text="播放"
android:layout_width="100dp"
android:layout_height="50dp"/>
<Button
android:id="@+id/btn_pause"
android:text="暂停"
android:layout_width="100dp"
android:layout_height="50dp"/>
<Button
android:id="@+id/btn_replay"
android:text="重放"
android:layout_width="100dp"
android:layout_height="50dp"/>
<Button
android:id="@+id/btn_stop"
android:text="停止"
android:layout_width="100dp"
android:layout_height="50dp"/>
</LinearLayout>
</RelativeLayout>
</FrameLayout>
</LinearLayout>
仓库地址:Coding
UI设计参考了Instagram和小红书,大约耗费了快两周时间从无到有,完成初期设想的70%,这个项目是能跑,但是少了页面资源管理和销毁,导致运行以后会在模拟器上留有很多页面。如果能有更多时间可以完善activity或许能做到代码复用性更高,更加优雅。
如果你觉得这个demo对你有帮助请点个赞,欢迎各位提出你们的idea或者提交分支来完善或者优化ta~,当然也欢迎各位学术大佬指出问题,看到有空会回复,谢谢大家!^o^