基础开发
listView
ListView就是列表条目,可以向下滚动,也可以点击。
首先设置两个视图布局
activity_main2.xml【充当容器{ListView}】
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/lv"/>
list_view_item.xml【充当容器中的组件{TextView}】
<TextView
android: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,就是textview
listView.setAdapter(new MyAdapter(data,this));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public 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;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return i;
}
/**
* //获取每个列表项的视图
* @param i 下标
* @param view 当前要显示或者是重用的列表项视图
* @param viewGroup 表示listview本身
* @return
*/
@Override
public 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存在,即视图对象存在,可以直接使用它,不用再创建视图对象,从容器中获取listview
TextView 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
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = parent.inflate(context, R.layout.recycler_view_item, null);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.tv.setText(data.get(position).getName());
}
@Override
public 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(){
@Override
public 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() {
@Override
public 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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv1"
android:textSize="30sp"
/>
</LinearLayout>
5、容器activity_main3.xml
<androidx.recyclerview.widget.RecyclerView
android: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(){
@Override
public 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
<!-- 测试补间动画 透明度 [从透明变到不透明,整个过程需要花费两秒钟]-->
<alpha
android:fromAlpha="0"
android:toAlpha="1"
android:duration="2000"
/>
<rotate
android: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"
/>
<translate
android: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() {
@Override
public 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() {
@Override
public 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() {
@Override
public void onAnimationStart(Animator animator) {
Log.e(TAG, "onAnimationStart: ");
}
@Override
public void onAnimationEnd(Animator animator) {
Log.e(TAG, "onAnimationEnd: " );
}
@Override
public void onAnimationCancel(Animator animator) {
Log.e(TAG, "onAnimationCancel: " );
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public 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设置的是px
LinearLayout.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;
}
@Override
public int getCount() {
return viewList.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
container.addView(viewList.get(position),0);
return viewList.get(position);
}
@Override
public 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.ViewPager
android: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">
<TextView
android: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;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public 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(){
@Override
public 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 -->
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="hello_blank_fragment----first"
android:id="@+id/tv_fragment"
/>
<Button
android: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-->
<fragment
android:name="com.pshdhx.demo1.fragment.BlankFragment1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fm"
/>
</LinearLayout>
4、主Activity绑定主布局
@Override
protected 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(){
@Override
public void onClick(View view) {
replaceFragment(new BlankFragment1());
}
});
btn2.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
replaceFragment(new ItemFragment());
}
});
}
//动态切换fragment
public void replaceFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.frameLayout,fragment);
transaction.addToBackStack(null);//入栈操作,方便手机下边的返回按钮操作,防止一点直接返回到桌面
transaction.commit();
}
主视图:
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn1"
android:text="change"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn2"
android:text="replace"/>
<FrameLayout
android: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(){
@Override
public void onClick(View view) {
//activity给fragment传递信息
BlankFragment1 bf1 = new BlankFragment1();
bf1.setFragmentCallback(new IFragmentCallback() {
@Override
public void sendMsgToActivity(String msg) {
// Log.e(TAG, "sendMsgToActivity: "+msg);
Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
}
@Override
public 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(){
@Override
public 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
@Override
public ViewPage2ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewPage2ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_pager, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewPage2ViewHolder holder, int position) {
holder.tv.setText(titleList.get(position));
holder.container.setBackgroundResource(colorList.get(position));
}
//这个有点重要呀,没有的话,界面为空!!
@Override
public 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 {
@Override
protected 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
@Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}
@Override
public int getItemCount() {
return fragmentList.size();
}
}
2、主方法
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager2;
@Override
protected 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;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mTextString = getArguments().getString(ARG_TEXT);
}
}
@Override
public 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;
@Override
protected 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() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
changeTab(position);
}
@Override
public 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);
//设置第一张图片为默认选中,且为当前图片ImageView
ivChat.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;
}
}
@Override
public 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的子组件-->
<LinearLayout
android: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">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/id_iv_weixin"
android:background="@drawable/tab_weixin">
</ImageView>
<TextView
android:layout_width="32dp"
android:layout_height="wrap_content"
android:id="@+id/text_weixin"
android:gravity="center"
android:text="微信"/>
</LinearLayout>
<LinearLayout
android: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">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/id_iv_contact"
android:background="@drawable/tab_contact">
</ImageView>
<TextView
android:layout_width="32dp"
android:layout_height="wrap_content"
android:id="@+id/text_contact"
android:gravity="center"
android:text="通讯录"/>
</LinearLayout>
<LinearLayout
android: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">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/id_iv_find"
android:background="@drawable/tab_find">
</ImageView>
<TextView
android:layout_width="32dp"
android:layout_height="wrap_content"
android:id="@+id/text_find"
android:gravity="center"
android:text="发信"/>
</LinearLayout>
<LinearLayout
android: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">
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/id_iv_profile"
android:background="@drawable/tab_profile">
</ImageView>
<TextView
android: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.ViewPager2
android: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
<application
android: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 {
@Override
public 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);
}
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="动态注册广播 发送广播区域"
android:textSize="20dp"
android:layout_marginTop="100dp"
android:layout_gravity="center_horizontal"/>
<Button
android: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(){
}
@GlideOption
public 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;
@Override
protected 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() {
@Override
public void onClick(View v) {
new Thread(){
@Override
public 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() {
@Override
public void onClick(View v) {
Call call = httpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public 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() {
@Override
public void onClick(View v) {
new Thread(){
@Override
public 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() {
@Override
public 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() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public 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() {
@Override
public 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() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
Log.e(TAG, "onFailure: "+e +"");
}
@Override
public 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() {
@Override
public void run() {
Interceptor interceptor = new Interceptor() {
@NotNull
@Override
public 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() {
@Override
public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {
cookieList = list;
}
@NotNull
@Override
public 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() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
Log.e(TAG, "onFailure: "+e );
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
Log.e(TAG, "onResponse: " + response.body().string());
}
});
}
}.start();
}