团队项目——第一阶段冲刺8
一、前言
1.昨天完成了:
将用户爱好选择存入数据库
2.今天完成了:
重构布局
3.明天的计划:
整合界面
二、成果展示
三、代码
1.爱好选择布局
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="48dp" android:background="#38353D" android:gravity="center" android:text="标签" android:textColor="@android:color/white" android:textSize="16dp" /> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/tv_remind" android:layout_width="match_parent" android:layout_height="46dp" android:background="@android:color/white" android:gravity="center_vertical" android:paddingLeft="15dp" android:text="我的标签(最多5个) " android:textSize="16dp" /> <com.me.view.FlowLayout android:id="@+id/tcy_my_label" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/white" android:padding="5dp" android:visibility="gone" custom:horizontalSpacing="6dp" custom:verticalSpacing="12dp" /> <View android:layout_width="match_parent" android:layout_height="10dp" android:background="#f6f6f6" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="46dp" android:background="@android:color/white"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:paddingLeft="15dp" android:text="推荐标签 " android:textSize="16dp" /> </RelativeLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#f6f6f6" /> <com.me.view.FlowLayout android:id="@+id/tcy_hot_label" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/white" android:padding="5dp" custom:horizontalSpacing="6dp" custom:verticalSpacing="12dp" /> </LinearLayout> </ScrollView> <Button android:id="@+id/bt_sub" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="提交" android:layout_margin="5dp"/> </LinearLayout>
2.登录布局
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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" tools:context=".MainActivity"> <EditText android:id="@+id/editTextPhoneNum" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:hint="手机号" android:inputType="textPersonName" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.161" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.11" /> <Button android:id="@+id/buttonCode" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="获取验证码" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.914" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.105" tools:text="获取验证码" /> <EditText android:id="@+id/editTextCode" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:hint="验证码" android:importantForAutofill="no" android:inputType="textPersonName" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.161" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.215" /> <Button android:id="@+id/buttonLogin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="登录" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.897" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.21" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintGuide_begin="568dp" app:layout_constraintGuide_percent="0.85" /> <ImageView android:id="@+id/imageView2" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.193" app:layout_constraintStart_toStartOf="parent" app:srcCompat="@drawable/wx_" /> <ImageView android:id="@+id/imageView3" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.793" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline3" app:layout_constraintVertical_bias="1.0" app:srcCompat="@drawable/qq" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintGuide_begin="578dp" app:layout_constraintGuide_percent="0.75" /> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="-----------其它方式-----------" android:textSize="18sp" app:layout_constraintBottom_toTopOf="@+id/guideline3" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline4" /> </androidx.constraintlayout.widget.ConstraintLayout>
3.爱好
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class FlowLayout extends ViewGroup { //每个item纵向间距 private int mVerticalSpacing; //每个item横向间距 private int mHorizontalSpacing; private BaseAdapter mAdapter; private TagItemClickListener mListener; private DataChangeObserver mObserver; public FlowLayout(Context context) { this(context, null); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); //获取自定义样式属性 TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FlowLayout, defStyle, 0); for (int i = 0; i < a.getIndexCount(); i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.FlowLayout_verticalSpacing: mVerticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 5); break; case R.styleable.FlowLayout_horizontalSpacing: mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 10); break; } } a.recycle(); } //负责设置子控件的测量模式和大小 根据所有子控件设置自己的宽和高 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式 int heighMode = MeasureSpec.getMode(heightMeasureSpec); int heighSize = MeasureSpec.getSize(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); //高 int height = 0; // 每一行的高度,累加至height int lineHeight = 0; // 在warp_content情况下,记录当前childView的左边的一个位置 int childLeft = getPaddingLeft(); // 在warp_content情况下,记录当前childView的上边的一个位置 int childTop = getPaddingTop(); // getChildCount得到子view的数目,遍历循环出每个子View for (int i = 0; i < getChildCount(); i++) { //拿到index上的子view View childView = getChildAt(i); // 测量每一个child的宽和高 measureChild(childView, widthMeasureSpec, heightMeasureSpec); //当前子空间实际占据的高度 int childHeight = childView.getMeasuredHeight(); //当前子空间实际占据的宽度 int childWidth = childView.getMeasuredWidth(); lineHeight = Math.max(childHeight, lineHeight);// 取最大值 //如果加入当前childView,超出最大宽度,则将目前最大宽度给width,类加height 然后开启新行 if (childWidth + childLeft + getPaddingRight() > widthSize) { childLeft = getPaddingLeft();// 重新开启新行,开始记录childLeft childTop += mVerticalSpacing + childHeight;// 叠加当前的高度 lineHeight = childHeight;// 开启记录下一行的高度 } else { //否则累加当前childView的宽度 childLeft += childWidth + mHorizontalSpacing; } } height += childTop + lineHeight + getPaddingBottom(); setMeasuredDimension(widthSize, heighMode == MeasureSpec.EXACTLY ? heighSize : height); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int width = r - l; int childLeft = getPaddingLeft(); int childTop = getPaddingTop(); int lineHeight = 0; //遍历所有childView根据其宽和高,计算子控件应该出现的位置 for (int i = 0; i < getChildCount(); i++) { final View childView = getChildAt(i); if (childView.getVisibility() == View.GONE) { continue; } int childWidth = childView.getMeasuredWidth(); int childHeight = childView.getMeasuredHeight(); lineHeight = Math.max(childHeight, lineHeight); // 如果已经需要换行 if (childLeft + childWidth + getPaddingRight() > width) { childLeft = getPaddingLeft(); childTop += mVerticalSpacing + lineHeight; lineHeight = childHeight; } childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); childLeft += childWidth + mHorizontalSpacing; } } private void drawLayout() { if (mAdapter == null || mAdapter.getCount() == 0) { return; } removeAllViews(); for (int i = 0; i < mAdapter.getCount(); i++) { View view = mAdapter.getView(i, null, null); final int position = i; view.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.itemClick(position); } } }); addView(view); } } public void setAdapter(BaseAdapter adapter) { if (mAdapter == null) { mAdapter = adapter; if (mObserver == null) { mObserver = new DataChangeObserver(); mAdapter.registerDataSetObserver(mObserver); } drawLayout(); } } public void setItemClickListener(TagItemClickListener mListener) { this.mListener = mListener; } public interface TagItemClickListener { void itemClick(int position); } class DataChangeObserver extends DataSetObserver { @Override public void onChanged() { drawLayout(); } @Override public void onInvalidated() { super.onInvalidated(); } } }
4.登录
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class LoginActivity extends AppCompatActivity { private Button buttonCode,buttonLogin; private EditText editTextPhoneNum,editTextCode; private String phoneNum,code; private EventHandler eh; private MyCountDownTimer myCountDownTimer = new MyCountDownTimer(30000,1000); private SentUrlTask sentUrlTask ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); buttonCode = findViewById(R.id.buttonCode); buttonLogin = findViewById(R.id.buttonLogin); editTextCode = findViewById(R.id.editTextCode); editTextPhoneNum = findViewById(R.id.editTextPhoneNum); buttonCode.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { phoneNum = editTextPhoneNum.getText().toString(); if(!phoneNum.isEmpty()){ if(Check.checkTel(phoneNum)){ //利用正则表达式获取检验手机号 // 获取验证码 SMSSDK.getVerificationCode("86", phoneNum); myCountDownTimer.start(); }else{ Toast.makeText(getApplicationContext(),"请输入有效的手机号",Toast.LENGTH_LONG).show(); } }else { Toast.makeText(getApplicationContext(),"请输入手机号",Toast.LENGTH_LONG).show(); return; } phoneNum = editTextPhoneNum.getText().toString(); } }); buttonLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { code = editTextCode.getText().toString(); if(!code.isEmpty()){ //提交验证码 SMSSDK.submitVerificationCode("86", phoneNum, code); }else{ Toast.makeText(getApplicationContext(),"请输入验证码",Toast.LENGTH_LONG).show(); return; } } }); eh = new EventHandler() { @Override public void afterEvent(int event, int result, Object data) { if (result == SMSSDK.RESULT_COMPLETE){ //回调完成 if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE) { //提交验证码成功 runOnUiThread(new Runnable() { @Override public void run() { success(phoneNum); Toast.makeText(LoginActivity.this,"登录成功",Toast.LENGTH_SHORT).show(); Intent intent = new Intent(LoginActivity.this, BottomNavigationActivity.class); startActivity(intent); } }); }else if (event == SMSSDK.EVENT_GET_VOICE_VERIFICATION_CODE){ runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(LoginActivity.this,"语音验证发送",Toast.LENGTH_SHORT).show(); } }); } else if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE){ //获取验证码成功 runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(LoginActivity.this,"验证码已发送",Toast.LENGTH_SHORT).show(); } }); }else if (event == SMSSDK.EVENT_GET_SUPPORTED_COUNTRIES){ } }else{ ((Throwable)data).printStackTrace(); Throwable throwable = (Throwable) data; throwable.printStackTrace(); try { JSONObject obj = new JSONObject(throwable.getMessage()); final String des = obj.optString("detail"); if (!TextUtils.isEmpty(des)){ runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(LoginActivity.this,des,Toast.LENGTH_SHORT).show(); } }); } } catch (JSONException e) { e.printStackTrace(); } } } }; //注册一个事件回调监听,用于处理SMSSDK接口请求的结果 SMSSDK.registerEventHandler(eh); } // 使用完EventHandler需注销,否则可能出现内存泄漏 @Override protected void onDestroy() { super.onDestroy(); SMSSDK.unregisterEventHandler(eh); } //倒计时类 private class MyCountDownTimer extends CountDownTimer { public MyCountDownTimer(long millisInFuture, long countDownInterval) { super(millisInFuture, countDownInterval); } //计时过程 @Override public void onTick(long l) { //防止计时过程中重复点击 buttonCode.setClickable(false); buttonCode.setText(l/1000+"秒"); } //计时完毕的方法 @Override public void onFinish() { //重新给Button设置文字 buttonCode.setText("重新获取"); //设置可点击 buttonCode.setClickable(true); } } public void success(String username){ sentUrlTask = new SentUrlTask("http://192.168.1.17:8080/NewsApi/news?method=addUser&username="+username); // sentUrlTask = new ListFragment.SentUrlTask("http://192.168.43.243:8080/NewsApi/news?method=allnews"); sentUrlTask.execute(); } private class SentUrlTask extends AsyncTask<Void,Void,String> { private String url; public SentUrlTask(String url) { this.url = url; } @Override protected String doInBackground(Void... voids) { return HttpUtil.setUrl(url); } @Override protected void onPostExecute(@NonNull String s) { super.onPostExecute(s); } } }