详细设计说明书:
需求概述
用户通过手机拍照或者手动上传等方式提交林业有害生物图像照片,经预览、裁剪等操作处理后上传至服务器进行识别。反馈害虫种类、识别率、个数等信息
基本功能需求
- 手机拍照或者手动上传图片;
- 林业有害生物基础库维护;
- 林业有害生物智能识别反馈。
非功能性需求
识别率达到90%以上,识别性能达到200ms以内
软件结构

更多
作品展示
设计过程
界面设置
主页页面
 显示点击操作状态: 
AI检测页面
 这个AI按钮点击操作, 这里的选择图片也就实现了拍照和相册  这里的检测按钮也就实现了离线检测和在线检测 
生物基础库页面
 也就是上面这个点击操作,点击之后,会进行向后端接口发送post请求,然后返回网图,提前布置好空的Imageview ,然后图片链接经过接口回来之后,直接进行插入即可(也就是说需要联网操作。)

然后点击相应的害虫就会有相应的详情显示,这些图片和文字都是动态初始化的,在后端进行相应修改之后也就进行了更新  这个页面的话,两个TextView 和一个ImageView 都是动态赋值,所填充的值也就是从后端传来的JSON对象中的标签对应的值。
项目设计代码
主页组件前端摆放心得体会:
布局套娃感想
 这三个按钮用一个relativelayout 里面包着三个LinearLayout ,每个Linearlayout 中放一个button ,这里为什么要加一个Linearlayout 呢,因为在线性布局里面可以加这个属性android:gravity ,控制它们的左中右,而左右的话,可以利用线性布局设置外边距来显得不贴边,这样的话,它们的相对位置不会改变的,因为间距并未写死,这里做出来最大的感想就是可以为一个组件可以加一个布局类,然后三个布局类在外面加一个布局类,套娃感想,只要设置属性之后不生效,立刻为它加一个单一的布局类。
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_marginTop="600dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="left"
android:layout_marginTop="50dp"
android:layout_marginLeft="5dp">
<Button
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="40dp"
android:background="@drawable/homepage_press"
android:layout_marginLeft="20dp"
android:layout_marginBottom="10dp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_marginTop="50dp"
>
<Button
android:layout_width="70dp"
android:id="@+id/AI"
android:layout_height="70dp"
android:background="@drawable/recognition_press"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="140dp"
android:layout_marginBottom="10dp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="20dp"
android:layout_marginTop="50dp"
android:gravity="right">
<Button
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="40dp"
android:background="@drawable/search_press"
android:layout_marginBottom="10dp"
/>
</LinearLayout>
</RelativeLayout>
专属线性布局
 首先要明白线性布局类,从左往右依次排放或者从上往下,因此在线性布局类里面,只要有关距离的属性都是没用的,只会依次排放,上面这图片摆明就是左边一个Imageview组件,右边一个线性布局,首先把右边这个线性布局类的orientation 属性设置成vertical ,这样线性布局里面放着三个TextView ,一个Imageview和一个线性布局都放在一个线性布局中,orientation 属性不用改,这样的话,从左往右就依次排放
<LinearLayout
android:id="@+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginTop="200dp">
<ImageView
android:id="@+id/image1"
android:layout_width="70dp"
android:layout_height="120dp"
android:src="@drawable/food"
android:layout_margin="5dp"></ImageView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_margin="3dp"
android:layout_marginLeft="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_margin="5dp"
android:text="农业害虫种类很多,鞘翅目、鳞翅目......你知道怎么辨别和防治吗? "
android:textColor="@color/dark"
android:textSize="18sp" />
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_margin="5dp"
android:text="农业害虫种类很多,鞘翅目、鳞翅目......你知道怎么辨别和防治吗? "
android:textColor="@color/dark"
android:textSize="14sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:textSize="14sp"
android:textColor="#77000000"
android:text="6970讨论 840.3万阅读"
/>
</LinearLayout>
</LinearLayout>
 这里也就是三个线性布局类 
方法1
而这里的话,也就很简单了,四个带有orientation 属性设置成vertical (垂直)的线性布局放在一个horizontal (水平)的线性布局类中,
方法2
如果要考虑合适间距问题的话(就只能用四个带有orientation 属性设置成vertical (垂直)的线性布局放在一个相对布局类里面):为每一个带有orientation 属性设置成vertical (垂直)的线性布局加一个带有 android:layout_width="match_parent" android:layout_height="match_parent" 的父类线性布局,然后在这个布局可以加gravity 属性,marginRight 等等属性(如果这里要用margin和gravity的话,那么父布局类就不能使用线性布局,而改用相对布局),因为间距属性针对于线性布局的子控件是无效的,只能在线性布局中统一设置。
主页后端点击操作的心得体会:
跳转AI检测页面
进行按钮监听,这里的按钮监听实现了点击状态和未点击状态。 在布局文件中搞一个selector ,然后在页面布局中直接把按钮background换成android:background="@drawable/search_press" 这个布局文件名字就行
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_pressed="false"
android:drawable="@drawable/search_presss"
/>
<item
android:state_pressed="true"
android:drawable="@drawable/search"
/>
</selector>
跳转生物基础库页面
感觉没什么好说的,也就是四张图片监听,然后利用intent进行activity跳转,如果想实现点迷人操作的话,那么可以试试overridePendingTransition 函数
AI检测页面组件前端摆放心得体会:
pop弹窗
 点击这个,当然这个按钮的话就不用说了,有手就行,会弹出如下的xml样式,  这里的话,主要是三个按钮放在一个线性布局中,记得需要把线性布局orientation="vertical" ,android:layout_alignParentBottom="true" ,这个的话,也就是贴底操作,至于父类的话,就直接用一个relativelayout 把线性布局类包起来就行,至于透明背景操作的话,动态初始化的时候,把背景颜色初始化为01000000 ,前面两位代表透明度,后面也就是rgb 喽
ColorDrawable dw = new ColorDrawable(0x01000000);
popupWindow.setBackgroundDrawable(dw);

列表选项控件Spinner
 点击一下检测按钮,紧接着就弹出一个Spinner 列表,然后直接进行监听
 在main.xml里面肯定就直接一个Spinner组件,
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="65dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="80dp"
android:dropDownWidth="match_parent"
android:layout_gravity="center"
android:background="@drawable/check_border"
android:dropDownHorizontalOffset="50dp"
android:textAlignment="center"/>
这个是用于android:textAlignment="center" 显示按钮的字体是否居中,而这个android:layout_centerHorizontal="true" 的话就是下拉列表的居中垂直,但是决定性布局因素还是动态设置的时候布局文件,
private static final String[] sSpiner={"检测","离线检测","在线检测"};
spinner = findViewById(R.id.spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.item_spinselect,sSpiner);
adapter.setDropDownViewResource(R.layout.item_spinselect);
spinner.setSelection(0);
spinner.setAdapter(adapter);
创建adapter 数组时,第一个参数传this,第二个也就是显示的布局文件,第三个也就是下拉的布局列表值,setDropDownViewResource 而这个也就是设置下拉的布局文件样式,setSelection(int pos)可以设置显示的位置 ,setAdapter 设置相应的适配器,然后呢,这里牵扯到了两个布局文件,第一个是显示的布局文件,第二个是下拉列表的布局文件,这两个可以一样,也可以不一样。举例布局文件如下:
<?xml version = "1.0" encoding = "utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:background="@drawable/check_border"
android:drawableLeft="@drawable/detect"
android:gravity="center" />
这个android:gravity="center" 也就是设置相应的字体居中
AI检测页面后端点击操作的心得体会:
pop弹窗
如何弹出pop弹窗
首选需要找到弹窗:
View popupWindowView = getLayoutInflater().inflate(R.layout.activity_camera, null);
内容,高度,宽度:
if(Location.BOTTOM.ordinal() == from){
popupWindow = new PopupWindow(popupWindowView, WindowManager.LayoutParams.FILL_PARENT, WindowManager.LayoutParams.WRAP_CONTENT, true);
}else{
popupWindow = new PopupWindow(popupWindowView, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.FILL_PARENT, true);
}
动画效果:
if(Location.BOTTOM.ordinal() == from){
popupWindow.setAnimationStyle(R.style.AnimationBottomFade);
}
菜单背景色:
ColorDrawable dw = new ColorDrawable(0x01000000);
popupWindow.setBackgroundDrawable(dw);
显示位置:
if(Location.BOTTOM.ordinal() == from){
popupWindow.showAtLocation(getLayoutInflater().inflate(R.layout.main, null), Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0);
}
关闭事件:
popupWindow.setOnDismissListener(new popupDismissListener());
class popupDismissListener implements PopupWindow.OnDismissListener{
@Override
public void onDismiss() {
backgroundAlpha(1f);
}
}
popupWindowView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if( popupWindow!=null && popupWindow.isShowing()){
popupWindow.dismiss();
popupWindow=null;
}
// 这里如果返回true的话,touch事件将被拦截
// 拦截后 PopupWindow的onTouchEvent不被调用,这样点击外部区域无法dismiss
return false;
}
});
拍照按钮实现
首先进行按钮监听:
bt_camera = (Button)popupWindowView.findViewById(R.id.bt_camera);
这里的话,需要打开相机需要申请权限,AndroidManifest中需要写入:
<uses-permission android:name="android.permission.CAMERA" />
然后需要动态申请:
String[] permissions = new String[]{
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.ACCESS_WIFI_STATE,
Manifest.permission.INTERNET,
Manifest.permission.MANAGE_EXTERNAL_STORAGE,
};
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.CAMERA}, 1);
} else {
openCamera();
popupWindow.dismiss();
}
Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getImageUri());
startActivityForResult(intent,100);
这里的话,打开相机拍照回来之后,需要把那个popwindow关闭,所以别忘了加一句 popupWindow.dismiss();
相册按钮实现
这里存储权限仍然需要动态申请,如上
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
动态申请代码一样。
Intent i = new Intent(Intent.ACTION_PICK);
i.setType("image/*");
startActivityForResult(i, SELECT_IMAGE);
这里的话,打开相册选择回来之后,需要把那个popwindow关闭,所以别忘了加一句 popupWindow.dismiss();
取消按钮实现
一个popupWindow.dismiss(); 即可
注意(flag设置):
这里的话拍照和相册的处理函数都是同一个onActivityResult ,所以的话,需要在这俩函数里面的设置一个flag,然后在处理函数里面进行分别处理,然后进行界面呈现即可。
注意(图片压缩):
进行拍照和选择后,需要把相片进行一定的压缩算法,否则无法放入ImageView 的,网上压缩算法挺多的,我贴一个 :
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public final class ImageTools {
public static Bitmap drawableToBitmap(Drawable drawable) {
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565;
Bitmap bitmap = Bitmap.createBitmap(w, h, config);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
drawable.draw(canvas);
return bitmap;
}
public static Drawable bitmapToDrawable(Bitmap bitmap) {
return new BitmapDrawable(bitmap);
}
public static Bitmap inputStreamToBitmap(InputStream inputStream)
throws Exception {
return BitmapFactory.decodeStream(inputStream);
}
public static Bitmap byteToBitmap(byte[] byteArray) {
if (byteArray.length != 0) {
return BitmapFactory
.decodeByteArray(byteArray, 0, byteArray.length);
} else {
return null;
}
}
public static Drawable byteToDrawable(byte[] byteArray) {
ByteArrayInputStream ins = null;
if (byteArray != null) {
ins = new ByteArrayInputStream(byteArray);
}
return Drawable.createFromStream(ins, null);
}
public static byte[] bitmapToBytes(Bitmap bm) {
byte[] bytes = null;
if (bm != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
bytes = baos.toByteArray();
}
return bytes;
}
public static byte[] drawableToBytes(Drawable drawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap bitmap = bitmapDrawable.getBitmap();
byte[] bytes = bitmapToBytes(bitmap);
;
return bytes;
}
// public static byte[] base64ToBytes(String base64) throws IOException {
// byte[] bytes = Base64.decode(base64);
// return bytes;
// }
//
//
// public static String bytesTobase64(byte[] bytes) {
// String base64 = Base64.encode(bytes);
// return base64;
// }
public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) {
final int reflectionGap = 4;
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix matrix = new Matrix();
matrix.preScale(1, -1);
Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, h / 2, w,
h / 2, matrix, false);
Bitmap bitmapWithReflection = Bitmap.createBitmap(w, (h + h / 2),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmapWithReflection);
canvas.drawBitmap(bitmap, 0, 0, null);
Paint deafalutPaint = new Paint();
canvas.drawRect(0, h, w, h + reflectionGap, deafalutPaint);
canvas.drawBitmap(reflectionImage, 0, h + reflectionGap, null);
Paint paint = new Paint();
LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0,
bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff,
0x00ffffff, Shader.TileMode.CLAMP);
paint.setShader(shader);
// Set the Transfer mode to be porter duff and destination in
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
// Draw a rectangle using the paint with our linear gradient
canvas.drawRect(0, h, w, bitmapWithReflection.getHeight()
+ reflectionGap, paint);
return bitmapWithReflection;
}
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Bitmap output = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, w, h);
final RectF rectF = new RectF(rect);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
public static Bitmap zoomBitmap(Bitmap bitmap, double width, double height) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix matrix = new Matrix();
float scaleWidth = ((float) width / w);
float scaleHeight = ((float) height / h);
matrix.postScale(scaleWidth, scaleHeight);
Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
return newbmp;
}
public static Drawable zoomDrawable(Drawable drawable, int w, int h) {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
Bitmap oldbmp = drawableToBitmap(drawable);
Matrix matrix = new Matrix();
float sx = ((float) w / width);
float sy = ((float) h / height);
matrix.postScale(sx, sy);
Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,
matrix, true);
return new BitmapDrawable(newbmp);
}
public static Bitmap getPhotoFromSDCard(String path,String photoName){
Bitmap photoBitmap = BitmapFactory.decodeFile(path + "/" +photoName +".png");
if (photoBitmap == null) {
return null;
}else {
return photoBitmap;
}
}
public static boolean checkSDCardAvailable(){
return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
}
public static boolean findPhotoFromSDCard(String path,String photoName){
boolean flag = false;
if (checkSDCardAvailable()) {
File dir = new File(path);
if (dir.exists()) {
File folders = new File(path);
File photoFile[] = folders.listFiles();
for (int i = 0; i < photoFile.length; i++) {
String fileName = photoFile[i].getName().split("\\.")[0];
if (fileName.equals(photoName)) {
flag = true;
}
}
}else {
flag = false;
}
// File file = new File(path + "/" + photoName + ".jpg" );
// if (file.exists()) {
// flag = true;
// }else {
// flag = false;
// }
}else {
flag = false;
}
return flag;
}
public static void savePhotoToSDCard(Bitmap photoBitmap, String path, String photoName){
if (checkSDCardAvailable()) {
File dir = new File(path);
if (!dir.exists()){
dir.mkdirs();
}
File photoFile = new File(path , photoName + ".png");
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(photoFile);
if (photoBitmap != null) {
if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) {
fileOutputStream.flush();
// fileOutputStream.close();
}
}
} catch (FileNotFoundException e) {
photoFile.delete();
e.printStackTrace();
} catch (IOException e) {
photoFile.delete();
e.printStackTrace();
} finally{
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void deleteAllPhoto(String path){
if (checkSDCardAvailable()) {
File folder = new File(path);
File[] files = folder.listFiles();
for (int i = 0; i < files.length; i++) {
files[i].delete();
}
}
}
//删除上一次截图的临时文件,包括图片路径和文件名称
public static void deletePhotoAtPathAndName(String path,String fileName){
if (checkSDCardAvailable()) {
File folder = new File(path);
File[] files = folder.listFiles();
for (int i = 0; i < files.length; i++) {
System.out.println(files[i].getName());
if (files[i].getName().equals(fileName)) {
files[i].delete();
}
}
}
}
}
列表选项控件Spinner
在线分析按钮实现
这个在线分析,只需要把图片进行base64 之后,然后发送post请求,然后进行后端设置,把分析好的图片呈现返回的result也设置为base64 ,塞进JsonObject 中,接收result,然后进行解码呈现即可
前提
这个需要联网操作
离线分析按钮实现
生物基础库页面组件前端摆放心得体会:

点击图片进行相应的跳转,  这里的话也就分为四个相对布局,一个相对布局里面有两个线性布局(属性设置为android:orientation="vertical" ),然后每一个线性布局里面下面有两个线性布局,分别放ImageView 和TextView ,为什么要用线性局部套在ImageView 和TextView 呢,这样可以对布局类 设置gravity以及marginLeft 值(可以设置左右偏移的话,那么父类的线性布局orientation属性肯定不是horizontal ,当 android:orientation=”horizontal” 时, 只有垂直方向的设置才起作用,水平方向的设置不起作用),这也印证了前面的相对布局作为父类为水平布局类而且android:orientation="vertical" ,代码如下:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="220dp"
android:layout_marginTop="40dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="210dp"
android:layout_marginTop="10dp"
android:orientation="vertical">
<LinearLayout
android:layout_marginLeft="20dp"
android:layout_width="match_parent"
android:layout_height="150dp"
android:gravity="left">
<ImageView
android:id="@+id/picture1"
android:layout_width="150dp"
android:layout_height="150dp">
</ImageView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="left"
android:layout_marginLeft="55dp"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textSize="15sp"
android:textColor="@color/dark"
android:text="梨小实心虫"
android:gravity="center_horizontal"
/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="210dp"
android:layout_marginTop="10dp"
android:orientation="vertical">
<LinearLayout
android:layout_marginRight="20dp"
android:layout_width="match_parent"
android:layout_height="150dp"
android:gravity="right">
<ImageView
android:id="@+id/picture2"
android:layout_width="150dp"
android:layout_height="150dp">
</ImageView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="right"
android:layout_marginRight="60dp"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textSize="15sp"
android:textColor="@color/dark"
android:text="梨小实心虫"
android:gravity="center_horizontal"
/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
这里搞出四份就可以了,如果需要滑动的话,只需要把布局类包进如下代码就行:
<ScrollView android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
</ScrollView>
然后点击后,进行详情跳转:  这里就很简单了,直接一个ImageView,外加两个textView,动态赋值即可:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
>
<ImageView
android:id="@+id/spider"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
>
</ImageView>
<TextView
android:id="@+id/title"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="275dp"
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="25sp"
>
</TextView>
<TextView
android:id="@+id/texts"
android:layout_marginTop="320dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="18sp"
>
</TextView>
</RelativeLayout>
还是那句话,如果需要下拉的话,加如下代码即可:
<ScrollView android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
</ScrollView>
生物基础库页面后端点击操作的心得体会:
插入网图
加入依赖在build.gardle
repositories {
google()
jcenter()
}
dependencies {
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}


或者maven
<dependency>
<groupId>com.github.bumptech.glide</groupId>
<artifactId>glide</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.github.bumptech.glide</groupId>
<artifactId>compiler</artifactId>
<version>4.12.0</version>
<optional>true</optional>
</dependency>
核心插入代码
Glide.with(this).load("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png").into(imgv);
作品展示

|