基础开发
listView
ListView就是列表条目,可以向下滚动,也可以点击。
首先设置两个视图布局
activity_main2.xml【充当容器{ListView}】
<ListViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/lv"/>
list_view_item.xml【充当容器中的组件{TextView}】<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/tv1"android:textSize="30sp"/>
设置主方法
private List<ListViewBean> data = new ArrayList<>();
public void testListView(){for (int i = 0; i < 100; i++) {ListViewBean bean = new ListViewBean();bean.setName("pansd"+i);data.add(bean);}ListView listView = findViewById(R.id.lv);//给listView组装item,就是textviewlistView.setAdapter(new MyAdapter(data,this));listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {Log.e("pansd - item - click", "onItemClick: "+i );}});
}
设置适配ListView的适配器(将TextView适配到其的item)
package com.pshdhx.demo1.adapter;
import android.content.Context;
import android.database.DataSetObserver;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.pshdhx.demo1.Bean.ListViewBean;
import com.pshdhx.demo1.R;
import java.util.List;
public class MyAdapter extends BaseAdapter {
private List<ListViewBean> data;private Context context;
public MyAdapter(List<ListViewBean> data, Context context) {this.data = data;this.context = context;}
@Overridepublic int getCount() {return data.size();}
@Overridepublic Object getItem(int i) {return null;}
@Overridepublic long getItemId(int i) {return i;}
/*** //获取每个列表项的视图* @param i 下标* @param view 当前要显示或者是重用的列表项视图* @param viewGroup 表示listview本身* @return*/@Overridepublic View getView(int i, View view, ViewGroup viewGroup) {if(view == null){ //第一次加载没有可重用的视图,LayoutInflater从布局文件中填充一个新试图,并将其分配给view对象//将子元素视图填充到父元素中view = LayoutInflater.from(context).inflate(R.layout.list_view_item,viewGroup,false);}//view存在,即视图对象存在,可以直接使用它,不用再创建视图对象,从容器中获取listviewTextView textView = view.findViewById(R.id.tv1);textView.setText(data.get(i).getName());Log.e("pansd", "getView: "+ i );return view;}
//由于view.findViewById(R.id.tv1); 每次进来时,比较耗时,所以把TextView抽取出来public View getView2(int i, View view, ViewGroup viewGroup) {ViewHolder viewHolder;if(view == null){viewHolder = new ViewHolder();view = LayoutInflater.from(context).inflate(R.layout.list_view_item,viewGroup,false);viewHolder.textView = view.findViewById(R.id.tv1);}else{
// 通过调用view.setTag(viewHolder);将ViewHolder对象设置为视图的标签,以便在以后进行重用。viewHolder = (ViewHolder) view.getTag();}viewHolder.textView.setText(data.get(i).getName());Log.e("pansd", "getView: "+ i );return view;}private final class ViewHolder{TextView textView;}
}
其余:
public class ListViewBean {String name;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
效果:
RecyclerView
1、导入包
build.gradle中
implementation 'androidx.recyclerview:recyclerview:1.1.0'
2、构造器,很重要,实现监听
package com.pshdhx.demo1.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.pshdhx.demo1.Bean.ListViewBean;
import com.pshdhx.demo1.R;
import java.util.List;
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {private List<ListViewBean> data;private Context context;
public RecyclerAdapter(List<ListViewBean> data, Context context) {this.data = data;this.context = context;}
@NonNull@Overridepublic MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = parent.inflate(context, R.layout.recycler_view_item, null);return new MyViewHolder(view);}
@Overridepublic void onBindViewHolder(@NonNull MyViewHolder holder, int position) {holder.tv.setText(data.get(position).getName());}
@Overridepublic int getItemCount() {return data == null ? 0 : data.size();}
public class MyViewHolder extends RecyclerView.ViewHolder {private TextView tv;public MyViewHolder(@NonNull View itemView) {super(itemView);tv = itemView.findViewById(R.id.tv1);itemView.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view) {if(onRecyclerItemClickListener != null){onRecyclerItemClickListener.onRecyclerItemClick(getAdapterPosition());}}});}}
private OnRecyclerItemClickListener onRecyclerItemClickListener;
public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener listener){onRecyclerItemClickListener = listener;}
public interface OnRecyclerItemClickListener{void onRecyclerItemClick(int position);}
}
3、主方法public void testRecyclerView(){for (int i = 0; i < 100; i++) {ListViewBean bean = new ListViewBean();bean.setName("pansd cycler"+i);data.add(bean);}RecyclerView recyclerView = findViewById(R.id.rv);//给listView组装item,就是textview
// recyclerView.setLayoutManager(new LinearLayoutManager(this));recyclerView.setLayoutManager(new GridLayoutManager(this,3)); //三个显示一行RecyclerAdapter recyclerAdapter = new RecyclerAdapter(data, this);recyclerAdapter.setOnRecyclerItemClickListener(new RecyclerAdapter.OnRecyclerItemClickListener() {@Overridepublic void onRecyclerItemClick(int position) {Log.e("pansd", "onRecyclerItemClick: "+ position);}});recyclerView.setAdapter(recyclerAdapter);}
4、recycler_view_item.xml<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/tv1"android:textSize="30sp"/>
</LinearLayout>
5、容器activity_main3.xml<androidx.recyclerview.widget.RecyclerViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/rv"
/>
动画类型
逐帧动画 frame-by-frame animation
F:\androidProject\android_learn\demo1\app\src\main\res\drawable\frame_list.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 创建逐帧动画 --><item android:drawable="@drawable/cat" android:duration="120"/><item android:drawable="@drawable/cat" android:duration="120"/><item android:drawable="@drawable/cat" android:duration="120"/>
</animation-list>
activity_main_framebyframe.xml<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/frameid"android:background="@drawable/frame_list"android:orientation="vertical"tools:context=".MainActivity">
</RelativeLayout>
/*** 测试逐帧动画*/
public void testframeByFrame(){setContentView(R.layout.activity_main_framebyframe);RelativeLayout relativeLayout = findViewById(R.id.frameid);final AnimationDrawable background = (AnimationDrawable) relativeLayout.getBackground();relativeLayout.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view) {if(flag){background.start();flag = false;Log.e(TAG, "onClick: 在运行" );}else{background.stop();flag = true;Log.e(TAG, "onClick: 已停止" );}}});
}
补间动画 tweened animation
1、透明度 alpha
2、旋转 rotate
3、缩放 scale
4、平移 translate
alpha.xml rotate.xml scale.xml translate.xml
<!-- 测试补间动画 透明度 [从透明变到不透明,整个过程需要花费两秒钟]-->
<alphaandroid:fromAlpha="0"android:toAlpha="1"android:duration="2000"/>
<rotateandroid:fromDegrees="0"android:toDegrees="360"android:pivotX="50%"android:pivotY="50%"android:duration="2000"/><scale
android:fromXScale="1"android:fromYScale="1"android:toXScale="0.5"android:toYScale="0.5"android:pivotX="50%"android:pivotY="50%"android:duration="2000"/><translateandroid:fromXDelta="0"android:fromYDelta="0"android:toXDelta="400"android:toYDelta="400"android:duration="2000"/>/*** 测试补间动画*/public void testBujianDonghua(){setContentView(R.layout.activity_main_tweened_animation);final ImageView imageView = findViewById(R.id.iv);imageView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {
// Animation animation = AnimationUtils.loadAnimation(MainActivity.this,
// R.anim.alpha);
// Animation animation = AnimationUtils.loadAnimation(MainActivity.this,
// R.anim.rotate);
// Animation animation = AnimationUtils.loadAnimation(MainActivity.this,
// R.anim.scale);Animation animation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.translate);imageView.startAnimation(animation);}});
属性动画 property animation/*** 测试属性动画 1*/
public void testPropertyAnimation1(){setContentView(R.layout.activity_main_tweened_animation);ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);valueAnimator.setDuration(2000);valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {float val = (float) valueAnimator.getAnimatedValue();Log.e(TAG, "onAnimationUpdate: "+val );}});valueAnimator.start();ImageView imageView = findViewById(R.id.iv);//将会由完全透明 变为不透明ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 1f);objectAnimator.setDuration(4000);objectAnimator.start();
objectAnimator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animator) {Log.e(TAG, "onAnimationStart: ");}
@Overridepublic void onAnimationEnd(Animator animator) {
Log.e(TAG, "onAnimationEnd: " );}
@Overridepublic void onAnimationCancel(Animator animator) {
Log.e(TAG, "onAnimationCancel: " );}
@Overridepublic void onAnimationRepeat(Animator animator) {
}});objectAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animation) {super.onAnimationStart(animation);Log.e(TAG, "只监听start方法...onAnimationStart: " );}});
}
单位尺寸
-
px: pixels(像素).不同设备显示效果相同
-
pt: point,是一个标准的长度单位,1pt= 1/72英寸,用于印刷业,非常简单易用
3、dip: device independent pixels(设备独立像素).不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素 4、dp:就是dip 5、sp: scaled pixels(放大像素).主要用于字体显示best for textsize。
6、LayoutParams相当于一个Layout的信息包,它封装了Layout的位置、高、宽等信息
/*** 测试像素*/public void testPx_dp_sp(){LinearLayout linearLayout = new LinearLayout( this);LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);linearLayout.setLayoutParams(layoutParams);TextView textview = new TextView(this);textview.setText("我是文本");// 这里的300设置的是pxLinearLayout.LayoutParams textLayoutParams = new LinearLayout.LayoutParams( 300, 300);
// textview.setLayoutParams(textLayoutParams);
// linearLayout.addView(textview);linearLayout.addView(textview,textLayoutParams);}
ViewPager
类似于左右滑动的轮播图===屏幕之间左右切换
重点:明白配置ViewPager作为容器的适配器
适配器代码:
public class ViewPagerAdapter extends PagerAdapter {List<View> viewList;
public ViewPagerAdapter(List<View> viewList) {this.viewList = viewList;}
@Overridepublic int getCount() {return viewList.size();}
@Overridepublic boolean isViewFromObject(@NonNull View view, @NonNull Object object) {return view == object;}
@NonNull@Overridepublic Object instantiateItem(@NonNull ViewGroup container, int position) {container.addView(viewList.get(position),0);return viewList.get(position);}
@Overridepublic void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {container.removeView(viewList.get(position));}
}
主方法:加载布局文件并将其转换成View对象的,用于在Android应用程序中显示用户界面,填充到主视图中。
/*** 测试ViewPager*/
public void testViewPager(){setContentView(R.layout.activity_main_view_pager);LayoutInflater lf = getLayoutInflater().from(this);View view1 = lf.inflate(R.layout.view_pager_layout1, null);View view2 = lf.inflate(R.layout.view_pager_layout2, null);View view3 = lf.inflate(R.layout.view_pager_layout3, null);List<View> viewList = new ArrayList<>();viewList.add(view1);viewList.add(view2);viewList.add(view3);
ViewPager viewPager = findViewById(R.id.vp);ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(viewList);viewPager.setAdapter(viewPagerAdapter);
}
<?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">
<!-- 效果,屏幕之间左右切换,像全屏的轮播图 --><androidx.viewpager.widget.ViewPagerandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/vp"/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:background="#ff0000"android:layout_height="match_parent">
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="layout1"android:textSize="80dp"/>
</LinearLayout>
Fragment
演示Fragment
类似于web中的iframe,点击一条栏目,该栏目的内容显示在Fragment中。
1、有自己的生命周期,可以嵌入到activity中,并且fragment可以复用
可以在activity在运行的时候动态添加删除,有自己的响应事件。
像是一个子activity
2、必须在activity中才能运行。所以其生命周期受到activity的限制。
代码:
新建Fragment,注意不是class
package com.pshdhx.demo1.fragment;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.pshdhx.demo1.R;
public class BlankFragment1 extends Fragment {
private View root;TextView tv;
@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
}
@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {if(root == null){root = inflater.inflate(R.layout.fragment_blank1,container,false);}tv = root.findViewById(R.id.tv_fragment);Button btn = root.findViewById(R.id.btn_fragment);
btn.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view) {tv.setText("hello fragment hhh");}});
return root;}
}
2、在新建Fragment的时候,自动把xml文件给添加好了,改布局为LinearLayout
<?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=".fragment.BlankFragment1">
<!-- TODO: Update blank fragment layout --><TextViewandroid:layout_width="match_parent"android:layout_height="100dp"android:text="hello_blank_fragment----first"android:id="@+id/tv_fragment"/>
<Buttonandroid:layout_width="match_parent"android:layout_height="100dp"android:id="@+id/btn_fragment"android:text="fragment中的按钮"/>
</LinearLayout>
3、将Fragment的xml绑定到主布局中
<?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">
<!-- 测试fragment--><fragmentandroid:name="com.pshdhx.demo1.fragment.BlankFragment1"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/fm"/>
</LinearLayout>
4、主Activity绑定主布局
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
// setContentView(R.layout.activity_main3);
// testRecyclerView();
// testBujianDonghua();
// testPropertyAnimation1();//testViewPager();testFragment();}
public void testFragment(){setContentView(R.layout.activity_main_fragment);
}
动态切换fragment
主方法:
public void testFragment2(){setContentView(R.layout.activity_main_fragment2);Button btn1 = findViewById(R.id.btn1);Button btn2 = findViewById(R.id.btn2);btn1.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view) {replaceFragment(new BlankFragment1());}});
btn2.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view) {replaceFragment(new ItemFragment());}});
}//动态切换fragmentpublic void replaceFragment(Fragment fragment){FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.replace(R.id.frameLayout,fragment);transaction.addToBackStack(null);//入栈操作,方便手机下边的返回按钮操作,防止一点直接返回到桌面transaction.commit();}
主视图:
<Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn1"android:text="change"/>
<Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn2"android:text="replace"/>
<FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:background="#ffff00"android:id="@+id/frameLayout"/>
新建两个Fragment 1个是空的 1个是item的,他们将放置在frameLayout的布局中,进行切换。
Activity与Fragment通信
Activity传递信息,使用Bundle对象
@Override
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Bundle bundle = getArguments();String message = (String) bundle.get("message");String message2 = bundle.getString("message");Log.e("pansd--", "onCreate: "+message+"---"+message2 );
}
Fragment获取信息,BlankFragment1.java@Override
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Bundle bundle = getArguments();String message = (String) bundle.get("message");String message2 = bundle.getString("message");Log.e("pansd--", "onCreate: "+message+"---"+message2 );
}
Fragment与Activity相互通信
利用面向对象的接口 MainActivity.java
/*** 1、测试Fragment的事件是小的activity* 2、测试fragment的切换* 3、利用IFragment接口测试fragment与Activity的通信*/public void testFragment2(){setContentView(R.layout.activity_main_fragment2);Button btn1 = findViewById(R.id.btn1);btn1.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view) {//activity给fragment传递信息BlankFragment1 bf1 = new BlankFragment1();bf1.setFragmentCallback(new IFragmentCallback() {@Overridepublic void sendMsgToActivity(String msg) {
// Log.e(TAG, "sendMsgToActivity: "+msg);Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();}
@Overridepublic String getMsgFromActivity(String msg) {return "hello fragment,this msg is from activity";}});replaceFragment(bf1);}});}
BlankFragment1.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {if(root == null){root = inflater.inflate(R.layout.fragment_blank1,container,false);}Button btn = root.findViewById(R.id.btn_fragment);btn.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view) {String msg = fragmentCallback.getMsgFromActivity("null");Toast.makeText(BlankFragment1.this.getContext(),msg,Toast.LENGTH_SHORT).show();fragmentCallback.sendMsgToActivity("hello activity,this msg from fragment");
}});
return root;
}
Debug流程走一遍之后,点击按钮,会先调用blank_fragment中的onClick方法,里边的方法会跳转到MainActivity中的onclick的方法,进而实现类似传递的效果。前提是接口被调用.[black_fragment和MainActitity的onclick方法都会被调用到]
Fragment的生命周期
Fragment的使用过程
1、点击按钮,打开Fragment
onCreate->onCreateView->onActitityCreated->onStart->onResume【即将可见,并开始响应用户输入】
2、直接返回到手机桌面
onPause->onStop
3、重新打开桌面
onStart->onResume
4、按后退键【整个应用彻底退出】
onPause->onStop->onDestroyView->onDestory->onDetach
5、如果在事务中,使用replace【替换,activity替换,先销毁之前的view,再加载新的view】fragment
onPause->onStop->onDestoryView
6、替换了之后,在按返回键
onCreateView【和5的最后一个相对应】->onActivityCreated->onstart->onResume
7、直接叉掉app
onDestory->onDetach
Fragment与PageView联合使用
viewPager2简介
先写下ViewPager2组件的介绍,优点是可以懒加载。
1、适配器
public class ViewPager2Adapter extends RecyclerView.Adapter<ViewPager2Adapter.ViewPage2ViewHolder> {
private List<String> titleList = new ArrayList<>();private List<Integer> colorList = new ArrayList<>();
private ViewPage2ViewHolder holder;
public ViewPager2Adapter(List<String> titleList, List<Integer> colorList, ViewPage2ViewHolder holder) {this.titleList = titleList;this.colorList = colorList;this.holder = holder;}
public ViewPager2Adapter() {
for (int i = 0; i < 10; i++) {titleList.add("title---" + i);}colorList.add(R.color.white1 );colorList.add(R.color.white2 );colorList.add(R.color.white3 );colorList.add(R.color.white4 );colorList.add(R.color.white1 );colorList.add(R.color.teal_200 );colorList.add(R.color.purple_700 );colorList.add(R.color.purple_500 );colorList.add(R.color.purple_200 );colorList.add(R.color.white1);}
@NonNull@Overridepublic ViewPage2ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {return new ViewPage2ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_pager, parent, false));}
@Overridepublic void onBindViewHolder(@NonNull ViewPage2ViewHolder holder, int position) {holder.tv.setText(titleList.get(position));holder.container.setBackgroundResource(colorList.get(position));}
//这个有点重要呀,没有的话,界面为空!!@Overridepublic int getItemCount() {return colorList.size();}
class ViewPage2ViewHolder extends RecyclerView.ViewHolder{
TextView tv;RelativeLayout container;
public ViewPage2ViewHolder(@NonNull View itemView) {super(itemView);container = itemView.findViewById(R.id.container);tv = itemView.findViewById(R.id.tv);}}
2、主类
public class MainActivity extends AppCompatActivity {
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);
ViewPager2 viewPage2 = findViewById(R.id.view_pager_2);viewPage2.setAdapter(new ViewPager2Adapter());
}
}
ViewPager与Fragment实现翻页效果
1、自定义适配器(Fragment和View一块的)
package com.pshdhx.viewpager2.adapter;
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.List;
public class MyFragmentPageAdapter extends FragmentStateAdapter {private List<Fragment> fragmentList;
public MyFragmentPageAdapter(@NonNull FragmentActivity fragmentActivity, List<Fragment> fragmentList) {super(fragmentActivity);this.fragmentList = fragmentList;}
public MyFragmentPageAdapter(@NonNull Fragment fragment, List<Fragment> fragmentList) {super(fragment);this.fragmentList = fragmentList;}
public MyFragmentPageAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<Fragment> fragmentList) {super(fragmentManager, lifecycle);this.fragmentList = fragmentList;}
@NonNull@Overridepublic Fragment createFragment(int position) {return fragmentList.get(position);}
@Overridepublic int getItemCount() {return fragmentList.size();}
}
2、主方法
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager2;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);
// ViewPager2 viewPager2 = findViewById(R.id.view_pager_2);
// viewPager2.setAdapter(new ViewPager2Adapter());initPage();}
/*** 测试Viewpage2与Fragment结合使用*/private void initPage() {viewPager2 = findViewById(R.id.view_pager_2);List<Fragment> fragmentList = new ArrayList<>();fragmentList.add(BlankFragment.newInstance("微信聊天"));fragmentList.add(BlankFragment.newInstance("通讯录"));fragmentList.add(BlankFragment.newInstance("发现"));fragmentList.add(BlankFragment.newInstance("我"));MyFragmentPageAdapter myFragmentPageAdapter = new MyFragmentPageAdapter(getSupportFragmentManager(), getLifecycle(), fragmentList);viewPager2.setAdapter(myFragmentPageAdapter);}
}
3、Fragment的配置方法
public class BlankFragment extends Fragment {
private View rootView;
private static final String ARG_TEXT = "param1";private String mTextString ;
public BlankFragment() {}
public static BlankFragment newInstance(String param1) {BlankFragment fragment = new BlankFragment();Bundle args = new Bundle();args.putString(ARG_TEXT, param1);fragment.setArguments(args);return fragment;}
@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (getArguments() != null) {mTextString = getArguments().getString(ARG_TEXT);}}
@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {if(rootView == null){rootView = inflater.inflate(R.layout.fragment_blank, container, false);}initView();return rootView;}
private void initView() {TextView textView = rootView.findViewById(R.id.fragment_tv);textView.setText(mTextString);}
}
案例:实现微信主界面跟随底部按钮的切换,或者是滑动切换。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ViewPager2 viewPager2;
private LinearLayout llchat,llContacts,llFind,llProfile;private ImageView ivChat,ivContacts,ivFind,ivProfile,ivCurrent;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);
// ViewPager2 viewPager2 = findViewById(R.id.view_pager_2);
// viewPager2.setAdapter(new ViewPager2Adapter());initPage();initTabView();}
/*** 测试Viewpage2与Fragment结合使用*/private void initPage() {viewPager2 = findViewById(R.id.view_pager_2);List<Fragment> fragmentList = new ArrayList<>();//设置fragment,主显示区域的内容fragmentList.add(BlankFragment.newInstance("微信聊天"));fragmentList.add(BlankFragment.newInstance("通讯录"));fragmentList.add(BlankFragment.newInstance("发现"));fragmentList.add(BlankFragment.newInstance("我"));MyFragmentPageAdapter myFragmentPageAdapter = new MyFragmentPageAdapter(getSupportFragmentManager(), getLifecycle(), fragmentList);viewPager2.setAdapter(myFragmentPageAdapter);//设置viewPager2的滑动窗口效果viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {super.onPageScrolled(position, positionOffset, positionOffsetPixels);}
@Overridepublic void onPageSelected(int position) {super.onPageSelected(position);changeTab(position);}
@Overridepublic void onPageScrollStateChanged(int state) {super.onPageScrollStateChanged(state);}});}
//初始化底部边框【四个tab=四个LinearLayout,还有每个tab中的图片】private void initTabView() {llchat = findViewById(R.id.id_tab_weixin);llchat.setOnClickListener(this);llContacts = findViewById(R.id.id_tab_contact);llContacts.setOnClickListener(this);llFind = findViewById(R.id.id_tab_find);llFind.setOnClickListener(this);llProfile = findViewById(R.id.id_tab_profile);llProfile.setOnClickListener(this);
ivChat = findViewById(R.id.id_iv_weixin);ivContacts = findViewById(R.id.id_iv_contact);ivFind = findViewById(R.id.id_iv_find);ivProfile = findViewById(R.id.id_iv_profile);
//设置第一张图片为默认选中,且为当前图片ImageViewivChat.setSelected(true);ivCurrent = ivChat;}
public void changeTab(int position){//取消图片选中ivCurrent.setSelected(false);switch (position){case R.id.id_tab_weixin:case 0://当前图片是选中状态ivChat.setSelected(true);//当前图片为此图片ivCurrent = ivChat;//当前fragment为第0个Fragment的内容viewPager2.setCurrentItem(0);break;case R.id.id_tab_contact:case 1:ivContacts.setSelected(true);ivCurrent = ivContacts;viewPager2.setCurrentItem(1);break;case R.id.id_tab_find:case 2:ivFind.setSelected(true);ivCurrent = ivFind;viewPager2.setCurrentItem(2);break;case R.id.id_tab_profile:case 3:ivProfile.setSelected(true);ivCurrent = ivProfile;viewPager2.setCurrentItem(3);break;}}
@Overridepublic void onClick(View view) {changeTab(view.getId());}
底部footer的xml,主要被主视图include即可
<?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="55dp"android:background="#ff0000"android:orientation="horizontal">
<!-- 设置四个footer的子组件--><LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:layout_gravity="center"android:gravity="center"android:orientation="vertical"android:id="@+id/id_tab_weixin"><ImageViewandroid:layout_width="32dp"android:layout_height="32dp"android:id="@+id/id_iv_weixin"android:background="@drawable/tab_weixin"></ImageView><TextViewandroid:layout_width="32dp"android:layout_height="wrap_content"android:id="@+id/text_weixin"android:gravity="center"android:text="微信"/></LinearLayout>
<LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:layout_gravity="center"android:gravity="center"android:orientation="vertical"android:id="@+id/id_tab_contact"><ImageViewandroid:layout_width="32dp"android:layout_height="32dp"android:id="@+id/id_iv_contact"android:background="@drawable/tab_contact"></ImageView><TextViewandroid:layout_width="32dp"android:layout_height="wrap_content"android:id="@+id/text_contact"android:gravity="center"android:text="通讯录"/></LinearLayout>
<LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:layout_gravity="center"android:gravity="center"android:orientation="vertical"android:id="@+id/id_tab_find"><ImageViewandroid:layout_width="32dp"android:layout_height="32dp"android:id="@+id/id_iv_find"android:background="@drawable/tab_find"></ImageView><TextViewandroid:layout_width="32dp"android:layout_height="wrap_content"android:id="@+id/text_find"android:gravity="center"android:text="发信"/></LinearLayout>
<LinearLayoutandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:layout_gravity="center"android:gravity="center"android:orientation="vertical"android:id="@+id/id_tab_profile"><ImageViewandroid:layout_width="32dp"android:layout_height="32dp"android:id="@+id/id_iv_profile"android:background="@drawable/tab_profile"></ImageView><TextViewandroid:layout_width="32dp"android:layout_height="wrap_content"android:id="@+id/text_profile"android:gravity="center"android:text="我"/></LinearLayout>
</LinearLayout>
include底部footer视图
<?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">
<!-- 设置显示区域页面--><androidx.viewpager2.widget.ViewPager2android:id="@+id/view_pager_2"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:background="#00ff00" />
<!-- 引入footer的组件--><include layout="@layout/bottom_layout"/>
</LinearLayout>
Activity
一个activity对应一个布局文件,一个activity必须要到清单文件中注册。
实例:一个activity跳转到另外一个activity
<applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>
<activity android:name=".MainActivity2"></activity>
</application>
public void startActivity(){startActivity(new Intent(this,MainActivity2.class));
}
Activity的生命周期
Service
service和activity类似,也是一个组件,运行在后台,需要在清单文件中注册使用【注意包名和路径】
<service android:name=".service.MyService01"/>
生命周期:
startService【执行onCreate->onStartCommand->onStart】
stopService【执行onDestory】
bindService【执行onCreate->onBind】
unbindService【执行onUnbind->onDestory】
消息广播
//测试动态广播
public class MyRevicer_Dynamic extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Log.e("pansd-动态接收者", "onReceive: ");}
}
注册到清单中,xml注册可能失效,但是java注册是可以的。
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main4);
MyRevicer_Dynamic revicer_dynamic = new MyRevicer_Dynamic();IntentFilter intentFilter = new IntentFilter();intentFilter.addAction("com.pshdhx.revicer_dynamic");registerReceiver(revicer_dynamic,intentFilter);
}
//动态广播按钮
public void sendDynamicAction(View view) {Intent intent = new Intent();intent.setAction("com.pshdhx.revicer_dynamic");sendBroadcast(intent);
}
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="动态注册广播 发送广播区域"android:textSize="20dp"android:layout_marginTop="100dp"android:layout_gravity="center_horizontal"/>
<Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="发送动态广播"android:onClick="sendDynamicAction"
android常用框架
热修复
见官方的demo文档。
主要流程是,将app的id注册到腾讯的buglg中,修复bug完成后,将修复包上传到buglg中,然后有bug的app会收到提醒,然后去buglg中下载补丁包,下载完成后,会强制重启app,此时已经完成修复。
官网:https://graph.qq.com/
官方文档:Android SDK 使用指南 - Bugly 文档
github的Demo地址:https://github.com/BuglyDevTeam/Bugly-Android-Demo/tree/master/BuglyHotfixDemo
高德地图SDK
1、搜索高德地图开放平台,注册登录
2、创建应用,获取keytool的秘钥,会生成appid,配置到gradle
3、通过gradle下载高德地图的依赖,或者是通过相关下载获取arr包到lib目录下,在用gradle增加lib目录,并引入arr包,可以避免冲突
4、开启配置{相关权限的读取配置、设置高德key的配置【生成的applicationID】到AndroidManifest.xml清单中}
5、设置layout.xml,引入地图。在Activity中按照文档和demo开始给地图添加功能。
6、POI关键词搜索功能
Glide图片加载库
可以加载本APP下的,手机内存中的,或是网络中的图片资源。
Glide v4 : 快速高效的Android图片加载库
GitHub - bumptech/glide: An image loading and caching library for Android focused on smooth scrolling
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
ImageView imageView = findViewById(R.id.iv);
Glide.with(this).load("https://img0.baidu.com/it/u=1435639120,2241364006&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500").into(imageView);
// Glide.with(this)
// .load("https://img0.baidu.com/it/u=1435639120,2241364006&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500")
// .apply(requestOptions)
// .transition(DrawableTransitionOptions.withCrossFade(fadeFactory))
// .transform(new CircleCrop())//设置圆
//
// .into(imageView);
简化操作:@GlideExtension
public class MyAppGlideExtension extends AppGlideModule {
private MyAppGlideExtension(){
}
@GlideOptionpublic static BaseRequestOptions<?> defaultImg(BaseRequestOptions<?> options){return options.placeholder(R.drawable.ic_launcher_foreground).error(R.drawable.error).fallback(R.drawable.fallback_null);}
}
@GlideModule
public class MyAppGlideModule extends AppGlideModule {
}
make project下,然后使用//使用此类,必须先make project下
GlideApp.with(this).load("xxxx").defaultImg()
.into(imageView);
网络加载框架
OKHttp
Http上传数据的编码格式类型【content-type】
HTTP content-type | 菜鸟教程
-
application/json: JSON数据格式
-
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
public class MainActivity extends AppCompatActivity {
private OkHttpClient httpClient;private String TAG = "pansd--";private TextView textView;
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);
httpClient = new OkHttpClient();textView = findViewById(R.id.reponseText);View getSyncBtn = findViewById(R.id.getSync);View getASyncBtn = findViewById(R.id.getASync);View postSyncBtn = findViewById(R.id.postSync);View postASyncBtn = findViewById(R.id.postASync);Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2").build();
getSyncBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {new Thread(){@Overridepublic void run() {Call call = httpClient.newCall(request);try {Response response = call.execute();Log.e(TAG, "testOkHttp: "+response.body().string() );} catch (IOException e) {e.printStackTrace();}}}.start();}});
getASyncBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Call call = httpClient.newCall(request);call.enqueue(new Callback() {@Overridepublic void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Overridepublic void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {if(response.isSuccessful()){Log.e(TAG, "onResponse: "+response.body().string() );}}});}});
postSyncBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {new Thread(){@Overridepublic void run() {FormBody formBody = new FormBody.Builder().add("a", "1").add("b", "2").build();Request requestPostSync = new Request.Builder().url("https://www.httpbin.org/post").post(formBody).build();Call call = httpClient.newCall(requestPostSync);try {Response response = call.execute();Log.e(TAG, "run: "+response.body().string() );} catch (IOException e) {e.printStackTrace();}}}.start();}});
postASyncBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {FormBody formBody = new FormBody.Builder().add("a", "1").add("b", "2").build();Request requestPostSync = new Request.Builder().url("https://www.httpbin.org/post").post(formBody).build();Call call = httpClient.newCall(requestPostSync);call.enqueue(new Callback() {@Overridepublic void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Overridepublic void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if(response.isSuccessful()){Log.e(TAG, "onResponse: "+response.body().string() );}}});}});
Button uploadFileBtn = findViewById(R.id.fileUpload);uploadFileBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.e(TAG, "onClick: "+ Environment.getExternalStorageDirectory() );File file = new File("C:\\Users\\Lenovo\\Desktop\\null.png");MultipartBody multipartBody = new MultipartBody.Builder().addFormDataPart("file", file.getName(), RequestBody.create(file, MediaType.parse("image/png"))).build();
Request fileRequest = new Request.Builder().url("https://www.httpbin.org/post").post(multipartBody).build();Call call = httpClient.newCall(fileRequest);call.enqueue(new Callback() {@Overridepublic void onFailure(@NotNull Call call, @NotNull IOException e) {
Log.e(TAG, "onFailure: "+e +"");}
@Overridepublic void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {if(response.isSuccessful()){Log.e(TAG, "文件上传__onClick: "+response.body().string() );}}});}});}
OKHTTP的自定义配置
okhttp新增拦截器+保存cookie
public void testInterceptorAndCookie(View view) {
new Thread() {@Overridepublic void run() {Interceptor interceptor = new Interceptor() {@NotNull@Overridepublic Response intercept(@NotNull Chain chain) throws IOException {Request request = chain.request().newBuilder().addHeader("os", "android").addHeader("username", "pansd").build();Response response = chain.proceed(request);return response;}
// Request request = new Request.Builder().url("https://httpbin.org/get?a=1&b=2").build();
// Call call = okHttpClient.newCall(request);
//
// call.enqueue(new Callback() {
// @Override
// public void onFailure(@NotNull Call call, @NotNull IOException e) {
// Log.e(TAG, "onFailure: "+"error"+e );
// }
//
// @Override
// public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
//
// if(response.isSuccessful()){
// Log.e(TAG, "testInterceptorAndCookie: "+response.body().string() );
// }
// }
// });};
OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(interceptor).cache(new Cache(new File("C:\\Users\\Lenovo\\Desktop"), 1024 * 1024)).cookieJar(new CookieJar() {@Overridepublic void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {cookieList = list;}
@NotNull@Overridepublic List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {if ("www.wanandroid.com".equals(httpUrl.host())) {return cookieList;}return cookieList;}}).build();
FormBody formBody = new FormBody.Builder().add("username", "hello_pans").add("password", "pan123").build();Request request1 = new Request.Builder().url("https://www.wanandroid.com/user/login").post(formBody).build();
Call call1 = okHttpClient.newCall(request1);try {Response response = call1.execute();Log.e(TAG, "testInterceptorAndCookie: " + response.body().string());} catch (IOException e) {e.printStackTrace();}
// call1.enqueue(new Callback() {
// @Override
// public void onFailure(@NotNull Call call, @NotNull IOException e) {
// Log.e(TAG, "testInterceptorAndCookie: "+e);
//
// }
//
// @Override
// public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
//
// Log.e(TAG, "testInterceptorAndCookie: "+response.body().string() );
//
// }
// });
Request req = new Request.Builder().url("https://www.wanandroid.com/lg/collect/list/0/json").build();
Call newCall = okHttpClient.newCall(req);newCall.enqueue(new Callback() {@Overridepublic void onFailure(@NotNull Call call, @NotNull IOException e) {
Log.e(TAG, "onFailure: "+e );}
@Overridepublic void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {Log.e(TAG, "onResponse: " + response.body().string());}});}}.start();
}