关于自定义View,可以磊加控件 的宽高,并且有进入动画,
向自定义View动态加入控件
import android.content.Context; import android.content.Intent; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import bwie.com.utils.SizeUtil; public class MyView extends ViewGroup { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } /** * 得到子View的宽高 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int endWidth = 0; int endHeight = 0; int childCount = getChildCount(); if(childCount>0){ for (int i = 0; i < childCount; i++) { View view = getChildAt(i); endHeight +=view.getMeasuredHeight(); measureChild(view,widthMeasureSpec,heightMeasureSpec); } } endWidth = SizeUtil.SizeData(getContext()); setMeasuredDimension(endWidth,endHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int left = 0,top=0,right = 0,bottom=0; int child = getChildCount(); for (int i = 0; i <child ; i++) { View view = getChildAt(i); view.layout(left,top,left + view.getMeasuredWidth(),top+view.getMeasuredHeight()); left += view.getMeasuredWidth(); top +=view.getMeasuredHeight(); if(left+view.getMeasuredWidth() > SizeUtil.SizeData(getContext())){ left=0; } view.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { TextView textView = (TextView) v; Log.e("textView:","=="+textView.getText().toString()); Intent intent = new Intent(getContext(),MainActivity.class); intent.putExtra("id",textView.getText().toString()); getContext().startActivity(intent); } }); view.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { removeView(v); return true; } }); } } }
关于自定义View的Activity
import android.animation.ObjectAnimator; import android.graphics.Color; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import bwie.com.R; import bwie.com.utils.SizeUtil; public class ThreeActivity extends AppCompatActivity implements View.OnClickListener { private Button add; private int count = 0; private MyView myView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_three); initView(); } private void initView() { add = findViewById(R.id.but_add); add.setOnClickListener(this); myView = findViewById(R.id.myView); } @Override public void onClick(View v) { count++; int width = SizeUtil.SizeData(this); // Log.e("OPPOPOPO","==="+width); TextView textView = new TextView(this); textView.setText(count+""); textView.setTextSize(16); textView.setGravity(Gravity.CENTER); textView.setTextColor(Color.BLACK); ObjectAnimator objectAnimator = ObjectAnimator .ofFloat(textView,"translationX",(width-width/3),0); objectAnimator.setDuration(2000); objectAnimator.start(); if(count == 1||count == 4||count == 7||count == 10||count == 13||count == 16||count == 19){ textView.setBackgroundColor(Color.RED); }else if(count == 2||count == 5||count == 8||count == 11||count == 14||count == 17||count == 20){ textView.setBackgroundColor(Color.YELLOW); }else { textView.setBackgroundColor(Color.BLUE); } myView.addView(textView); //View的参数 ViewGroup.LayoutParams params = textView.getLayoutParams(); params.width = width/3; params.height = 70; textView.setLayoutParams(params); } }
工具类参上:
判断网络是否链接的工具类,需要添加权限
import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; public class NetUtil { public static boolean isConn(Context context){ //1.得到系统服务 ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); //2.得到网络信息类对象-需要添加权限 NetworkInfo info = manager.getActiveNetworkInfo(); //3.进行判断 if(info!=null && info.isAvailable()){//已经连接网络 return true; }else{ return false; } } }
OkHttp请求网络工具类
单例模式、二次封装、应用拦截器、get、post封装
import java.util.HashMap; import java.util.Iterator; import okhttp3.Callback; import okhttp3.FormBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.logging.HttpLoggingInterceptor; public class OkHttpUtils { private static OkHttpUtils okHttpUtils; private OkHttpClient okHttpClient; private OkHttpUtils() { okHttpClient = new OkHttpClient.Builder() .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) .build(); } public static OkHttpUtils getINSTANCE(){ if(okHttpUtils == null){ okHttpUtils = new OkHttpUtils(); } return okHttpUtils; } public void getGet(String str, Callback callback){ Request request = new Request.Builder() .get() .url(str) .build(); okHttpClient.newCall(request).enqueue(callback); } public void getPost(String str, HashMap<String,String> map,Callback callback){ FormBody.Builder builder = new FormBody.Builder(); Iterator<String> iterator = map.keySet().iterator(); while (iterator.hasNext()){ String key = iterator.next(); String value = map.get(key); builder.add(key,value); } Request request = new Request.Builder() .post(builder.build()) .url(str) .build(); okHttpClient.newCall(request).enqueue(callback); } }
获得整个屏幕的宽度
自定义View时使用
import android.content.Context; import android.util.DisplayMetrics; public class SizeUtil { public static int SizeData(Context context){ DisplayMetrics metrics = context.getResources().getDisplayMetrics(); return metrics.widthPixels; } }
MVP参上:
model:
import bwie.com.presenter.MyPresenterInterface; import bwie.com.utils.OkHttpUtils; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Response; public class MyModel { public void getDate(String str, final MyPresenterInterface myPresenterInterface) { OkHttpUtils.getINSTANCE().getGet(str, new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful() && response.code() == 200) { String s = response.body().string(); myPresenterInterface.onSuccess(s); } } }); } public void postDate(final String str, HashMap<String, String> map, final MyPresenterInterface myPresenterInterface) { OkHttpUtils.getINSTANCE().getPost(str, map, new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful() && response.code() == 200) { String s = response.body().string(); myPresenterInterface.onSuccess(s); } } }); } }
presenter
解绑与绑定
字符串替换是因为请求的数据格式不对,重新修饰一下
import java.util.HashMap; import bwie.com.model.MyModel; import bwie.com.view.MyViewInterface; public class MyPresenter implements MyPresenterInterface { private MyModel myModel; private MyViewInterface myViewInterface; public MyPresenter(MyViewInterface myViewInterface) { this.myModel = new MyModel(); atachView(myViewInterface); } /** * 绑定 * * @param myViewInterface */ public void atachView(MyViewInterface myViewInterface) { this.myViewInterface = myViewInterface; } /** * 解绑 */ public void detachView() { if (myViewInterface != null) { myViewInterface = null; } } public void getDate(String str) { myModel.getDate(str, this); } public void postDate(String str, HashMap<String, String> map) { myModel.postDate(str, map, this); } @Override public void onSuccess(Object obj) { String s = (String) obj; String str = s.replace("null(", "").replace(")", ""); myViewInterface.onSuccess(str); } }
presenter的接口
public interface MyPresenterInterface { void onSuccess(Object obj); }
Activity的基类
import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; public abstract class BaseActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(setView()); initView(); initDate(); } abstract void initView(); abstract void initDate(); abstract int setView(); }
view
继承基类的MainActivity
XRecyclerView实现刷新与加载,请求网络时进行判断,如果有网络,请求进行显示并进行数据库存储,如果没有网络链接,使用上次存到数据库中的数据进行处理与展示
import android.content.ContentValues; import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.widget.Toast; import com.google.gson.Gson; import com.jcodecraeer.xrecyclerview.XRecyclerView; import java.util.HashMap; import java.util.List; import bwie.com.R; import bwie.com.adapter.XRecyclerAdapter; import bwie.com.common.Contants; import bwie.com.db.DbHelper; import bwie.com.model.BeanAll.NewsBean; import bwie.com.presenter.MyPresenter; import bwie.com.utils.NetUtil; public class MainActivity extends BaseActivity implements MyViewInterface { private XRecyclerView xrcv; private int page = 5010; private boolean isRefresh = true; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); String s = (String) msg.obj; Gson gson = new Gson(); NewsBean newsBean = gson.fromJson(s, NewsBean.class); List<NewsBean.DataBean> list = newsBean.getData(); if(isRefresh){ adapter = new XRecyclerAdapter(list, MainActivity.this); xrcv.setAdapter(adapter); xrcv.refreshComplete(); SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put("json",s); db.insert(DbHelper.DB_TABLE,null,contentValues); }else{ if(adapter!=null){ adapter.loadMore(list); } xrcv.loadMoreComplete(); } } }; private MyPresenter presenter; private DbHelper dbHelper; private XRecyclerAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(R.layout.activity_main); initView(); initDate(); } @Override void initView() { xrcv = (XRecyclerView) findViewById(R.id.xrcv); xrcv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); xrcv.setItemAnimator(new DefaultItemAnimator()); xrcv.setPullRefreshEnabled(true); xrcv.setLoadingMoreEnabled(true); xrcv.setLoadingListener(new XRecyclerView.LoadingListener() { @Override public void onRefresh() { isRefresh = true; page = 5010; request(); xrcv.refreshComplete(); } @Override public void onLoadMore() { isRefresh = false; page++; request(); xrcv.loadMoreComplete(); } }); } @Override void initDate() { presenter = new MyPresenter(this); dbHelper = new DbHelper(this); request(); } private void request() { Intent intent = getIntent(); String id = intent.getExtras().getString("id"); page = 5010+Integer.parseInt(id); if(NetUtil.isConn(this)){ HashMap<String, String> map = new HashMap<>(); map.put("type", page + ""); presenter.postDate(Contants.POST_URl, map); }else{ Toast.makeText(this,"无网络链接!",Toast.LENGTH_SHORT).show(); String json = null; SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = db.rawQuery("select * from news", null); while (cursor.moveToNext()){ json = cursor.getString(cursor.getColumnIndex("json")); } NewsBean newsBean = new Gson().fromJson(json,NewsBean.class); XRecyclerAdapter adapter = new XRecyclerAdapter(newsBean.getData(),MainActivity.this); xrcv.setAdapter(adapter); } } @Override int setView() { return R.layout.activity_main; } @Override public void onSuccess(Object obj) { String s = (String) obj; Message msg = Message.obtain(); msg.obj = s; handler.sendMessage(msg); } @Override protected void onDestroy() { super.onDestroy(); presenter.detachView(); } }
view的接口:
public interface MyViewInterface { void onSuccess(Object obj); }
XRecyclerView的适配器,并且多条目加载,其中有长按删除:
import android.content.Context; import android.content.DialogInterface; import android.support.annotation.NonNull; import android.support.v7.app.AlertDialog; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import com.jcodecraeer.xrecyclerview.XRecyclerView; import java.util.List; import bwie.com.R; import bwie.com.common.Contants; import bwie.com.model.BeanAll.NewsBean; public class XRecyclerAdapter extends XRecyclerView.Adapter<XRecyclerView.ViewHolder> { private List<NewsBean.DataBean> list; private Context context; public XRecyclerAdapter(List<NewsBean.DataBean> list, Context context) { this.list = list; this.context = context; } public void loadMore(List<NewsBean.DataBean> data){ if(list!=null){ list.addAll(data); notifyDataSetChanged(); } } @NonNull @Override public XRecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if(viewType == Contants.TYPE1){ View view = View.inflate(context, R.layout.item_rcv1,null); return new HolderType1(view); }else{ View view = View.inflate(context, R.layout.item_rcv3,null); return new HolderType3(view); } } @Override public void onBindViewHolder(@NonNull final XRecyclerView.ViewHolder holder, int position) { holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle("确定删除吗?"); builder.setNegativeButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { int p = holder.getLayoutPosition(); Log.e("Pos","p:"+p); list.remove(p-1); notifyItemRemoved(p); } }); builder.setNeutralButton("取消",null); builder.show(); return true; } }); NewsBean.DataBean data = list.get(position); if(holder instanceof HolderType1){ Glide.with(context).load(data.getMiniimg().get(0).getSrc()).into(((HolderType1) holder).img); ((HolderType1) holder).title.setText(data.getTopic()); ((HolderType1) holder).time.setText(data.getDate()+" "+data.getSource()); }else if(holder instanceof HolderType3){ ((HolderType3) holder).title.setText(data.getTopic()); ((HolderType3) holder).time.setText(data.getDate()+" "+data.getSource()); if(data.getMiniimg()!=null && data.getMiniimg().size()>0){ if(data.getMiniimg().size() == 1){ Glide.with(context).load(data.getMiniimg().get(0).getSrc()).into(((HolderType3) holder).img1); Glide.with(context).load(data.getMiniimg().get(0).getSrc()).into(((HolderType3) holder).img2); Glide.with(context).load(data.getMiniimg().get(0).getSrc()).into(((HolderType3) holder).img3); }else if(data.getMiniimg().size() == 2){ Glide.with(context).load(data.getMiniimg().get(1).getSrc()).into(((HolderType3) holder).img1); Glide.with(context).load(data.getMiniimg().get(0).getSrc()).into(((HolderType3) holder).img2); Glide.with(context).load(data.getMiniimg().get(1).getSrc()).into(((HolderType3) holder).img3); }else { Glide.with(context).load(data.getMiniimg().get(0).getSrc()).into(((HolderType3) holder).img1); Glide.with(context).load(data.getMiniimg().get(1).getSrc()).into(((HolderType3) holder).img2); Glide.with(context).load(data.getMiniimg().get(2).getSrc()).into(((HolderType3) holder).img3); } } } } @Override public int getItemViewType(int position) { return position%3==2?Contants.TYPE1:Contants.TYPE3; } @Override public int getItemCount() { return list.size(); } class HolderType1 extends XRecyclerView.ViewHolder{ ImageView img; TextView title; TextView time; public HolderType1(View itemView) { super(itemView); img = itemView.findViewById(R.id.rcv1_img); title = itemView.findViewById(R.id.rcv1_text); time = itemView.findViewById(R.id.rcv1_ts); } } class HolderType3 extends XRecyclerView.ViewHolder{ ImageView img1,img2,img3; TextView title,time; public HolderType3(View itemView) { super(itemView); img1 = itemView.findViewById(R.id.rcv3_img1); img2 = itemView.findViewById(R.id.rcv3_img2); img3 = itemView.findViewById(R.id.rcv3_img3); title = itemView.findViewById(R.id.rcv3_text); time = itemView.findViewById(R.id.rcv3_ts); } } }
关于数据库的创建,表的创建:
import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DbHelper extends SQLiteOpenHelper { private static String DB_NAME = "news.db"; public static String DB_TABLE = "news"; public DbHelper(Context context) { super(context, DB_NAME, null, 1); } @Override public void onCreate(SQLiteDatabase db) { String sql = "create table "+DB_TABLE+" (_id Integer PRIMARY KEY,json text) "; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
全局需要:
public class Contants { public static String POST_URl = "http://ttpc.dftoutiao.com/jsonpc/refresh"; public static int TYPE1 = 1; public static int TYPE3 = 3; }
布局文件:
多条目1:
<?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" android:orientation="horizontal" android:padding="5dp"> <ImageView android:id="@+id/rcv1_img" android:layout_width="0dp" android:layout_height="70dp" android:layout_weight="2" android:scaleType="centerCrop" android:src="@mipmap/ic_launcher" /> <RelativeLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_weight="7"> <TextView android:id="@+id/rcv1_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="2" android:text="上的讲话不舒服就k看到世讲话不舒服就k看到世界很疯狂就" android:textSize="16dp" android:textStyle="bold" /> <TextView android:id="@+id/rcv1_ts" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/rcv1_text" android:layout_marginTop="10dp" android:text="即使对方" android:textSize="12dp" /> </RelativeLayout> </LinearLayout>
多条目2:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="5dp"> <TextView android:id="@+id/rcv3_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="end" android:singleLine="true" android:text="肯德基和疯狂的女人给会计的女人给会计年度浮亏加拿大" android:textSize="16dp" android:textStyle="bold" /> <LinearLayout android:id="@+id/lin" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/rcv3_text" android:layout_marginBottom="5dp" android:layout_marginTop="5dp" android:orientation="horizontal"> <ImageView android:id="@+id/rcv3_img1" android:layout_width="0dp" android:layout_height="70dp" android:layout_weight="1" android:scaleType="centerCrop" android:src="@mipmap/ic_launcher" /> <ImageView android:id="@+id/rcv3_img2" android:layout_width="0dp" android:layout_height="70dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_weight="1" android:scaleType="centerCrop" android:src="@mipmap/ic_launcher" /> <ImageView android:id="@+id/rcv3_img3" android:layout_width="0dp" android:layout_height="70dp" android:layout_weight="1" android:scaleType="centerCrop" android:src="@mipmap/ic_launcher" /> </LinearLayout> <TextView android:id="@+id/rcv3_ts" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/lin" android:layout_marginLeft="5dp" android:layout_marginTop="5dp" android:text="的疯狂就是如果你 看到妇女你" android:textSize="12dp" /> </RelativeLayout>
权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" />
依赖:
implementation 'com.squareup.okhttp3:okhttp:3.10.0' implementation 'com.github.bumptech.glide:glide:4.7.1' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' implementation 'com.jcodecraeer:xrecyclerview:1.5.9'